2
0
mirror of https://github.com/boostorg/mysql.git synced 2026-02-14 00:42:53 +00:00

Return to OO API

This commit is contained in:
Ruben Perez
2022-10-05 17:24:06 +02:00
parent 03e892bc20
commit f80d59d0b3
18 changed files with 994 additions and 819 deletions

View File

@@ -14,14 +14,10 @@
#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/error.hpp>
#include <boost/mysql/resultset_base.hpp>
#include <boost/mysql/statement_base.hpp>
#include <boost/mysql/resultset.hpp>
#include <boost/mysql/statement.hpp>
#include <boost/mysql/connection_params.hpp>
#include <boost/mysql/execute_params.hpp>
#include <boost/mysql/row_view.hpp>
#include <boost/mysql/rows_view.hpp>
#include <type_traits>
#endif
@@ -128,13 +124,16 @@ public:
executor_type get_executor() { return get_channel().get_executor(); }
/// The `Stream` type this connection is using.
using next_layer_type = Stream;
using stream_type = Stream;
/// Retrieves the underlying Stream object.
Stream& next_layer() { return get_channel().next_layer(); }
Stream& stream() { return get_channel().next_layer(); }
/// Retrieves the underlying Stream object.
const Stream& next_layer() const { return get_channel().next_layer(); }
const Stream& stream() const { return get_channel().next_layer(); }
using statement_type = statement<Stream>;
using resultset_type = resultset<Stream>;
/**
* \brief Returns whether the connection uses SSL or not.
@@ -341,7 +340,7 @@ public:
* before calling any function that involves communication with the server over this
* connection. Otherwise, the results are undefined.
*/
void query(boost::string_view query_string, resultset_base& result, error_code&, error_info&);
void query(boost::string_view query_string, resultset<Stream>& result, error_code&, error_info&);
/**
* \brief Executes a SQL text query (sync with exceptions version).
@@ -351,7 +350,7 @@ public:
* before calling any function that involves communication with the server over this
* connection. Otherwise, the results are undefined.
*/
void query(boost::string_view query_string, resultset_base& result);
void query(boost::string_view query_string, resultset<Stream>& result);
/**
* \brief Executes a SQL text query (async without [reflink error_info] version).
@@ -372,7 +371,7 @@ public:
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code))
async_query(
boost::string_view query_string,
resultset_base& result,
resultset<Stream>& result,
CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)
)
{
@@ -398,7 +397,7 @@ public:
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code))
async_query(
boost::string_view query_string,
resultset_base& result,
resultset<Stream>& result,
error_info& output_info,
CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)
);
@@ -409,7 +408,7 @@ public:
* Prepared statements are only valid while the connection object on which
* this function was called is alive and open.
*/
void prepare_statement(boost::string_view statement, statement_base& result, error_code&, error_info&);
void prepare_statement(boost::string_view stmt, statement<Stream>& result, error_code&, error_info&);
/**
* \brief Prepares a statement (sync with exceptions version).
@@ -417,7 +416,7 @@ public:
* Prepared statements are only valid while the connection object on which
* this function was called is alive and open.
*/
void prepare_statement(boost::string_view statement, statement_base& result);
void prepare_statement(boost::string_view stmt, statement<Stream>& result);
/**
* \brief Prepares a statement (async without [reflink error_info] version).
@@ -435,12 +434,12 @@ public:
>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code))
async_prepare_statement(
boost::string_view statement,
statement_base& result,
boost::string_view stmt,
statement<Stream>& result,
CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)
)
{
return async_prepare_statement(statement, result, shared_info(), std::forward<CompletionToken>(token));
return async_prepare_statement(stmt, result, shared_info(), std::forward<CompletionToken>(token));
}
/**
@@ -459,471 +458,8 @@ public:
>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code))
async_prepare_statement(
boost::string_view statement,
statement_base& 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
* FieldViewCollection should meet the [reflink FieldViewCollection] requirements.
*
* After this function has returned, you should read the entire resultset_base
* before calling any function that involves communication with the server over this
* connection. Otherwise, the results are undefined.
*/
template <class FieldViewCollection, class EnableIf = detail::enable_if_field_view_collection<FieldViewCollection>>
void execute_statement(
const statement_base& statement,
const FieldViewCollection& params,
resultset_base& 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
* FieldViewCollection should meet the [reflink FieldViewCollection] requirements.
*
* After this function has returned, you should read the entire resultset_base
* before calling any function that involves communication with the server over this
* connection. Otherwise, the results are undefined.
*/
template <class FieldViewCollection, class EnableIf = detail::enable_if_field_view_collection<FieldViewCollection>>
void execute_statement(
const statement_base& statement,
const FieldViewCollection& params,
resultset_base& result
)
{
return execute_statement(make_execute_params(statement, params), result);
}
/**
* \brief Executes a statement (collection,
* async without [reflink error_info] version).
* \details
* FieldViewCollection should meet the [reflink FieldViewCollection] requirements.
*
* After this operation completes, you should read the entire resultset_base
* 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_base<Stream>)`.
*/
template<
class FieldViewCollection,
BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))
CompletionToken
BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type),
class EnableIf = detail::enable_if_field_view_collection<FieldViewCollection>
>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code))
async_execute_statement(
const statement_base& statement,
const FieldViewCollection& params,
resultset_base& 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
* FieldViewCollection should meet the [reflink FieldViewCollection] requirements.
*
* After this operation completes, you should read the entire resultset_base
* 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_base<Stream>)`.
*/
template <
class FieldViewCollection,
BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))
CompletionToken
BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type),
class EnableIf = detail::enable_if_field_view_collection<FieldViewCollection>
>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code))
async_execute_statement(
const statement_base& statement,
const FieldViewCollection& params,
resultset_base& 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
* FieldViewFwdIterator should meet the [reflink FieldViewFwdIterator] 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_base
* before calling any function that involves communication with the server over this
* connection. Otherwise, the results are undefined.
*/
template <class FieldViewFwdIterator>
void execute_statement(
const execute_params<FieldViewFwdIterator>& params,
resultset_base& result,
error_code& ec,
error_info& info
);
/**
* \brief Executes a statement (`execute_params`, sync with exceptions version).
* \details
* FieldViewFwdIterator should meet the [reflink FieldViewFwdIterator] 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_base
* before calling any function that involves communication with the server over this
* connection. Otherwise, the results are undefined.
*/
template <class FieldViewFwdIterator>
void execute_statement(
const execute_params<FieldViewFwdIterator>& params,
resultset_base& result
);
/**
* \brief Executes a statement (`execute_params`,
* async without [reflink error_info] version).
* \details
* FieldViewFwdIterator should meet the [reflink FieldViewFwdIterator] 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_base
* 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_base<Stream>)`.
*/
template <
class FieldViewFwdIterator,
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<FieldViewFwdIterator>& params,
resultset_base& 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
* FieldViewFwdIterator should meet the [reflink FieldViewFwdIterator] 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_base
* 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_base<Stream>)`.
*/
template <
class FieldViewFwdIterator,
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<FieldViewFwdIterator>& params,
resultset_base& 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 statement_base&, 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 statement_base&);
/**
* \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 statement_base& 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 statement_base& 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_base 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_base& resultset_base, row_view& 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_base 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_base& resultset_base, row_view& 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_base 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_base& resultset_base,
row_view& output,
CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)
)
{
return async_read_one_row(resultset_base, 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_base 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_base& resultset_base,
row_view& output,
error_info& output_info,
CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)
);
void read_some_rows(resultset_base& resultset_base, rows_view& output, error_code& err, error_info& info);
void read_some_rows(resultset_base& resultset_base, 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))
CompletionToken
BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)
>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code))
async_read_some_rows(
resultset_base& resultset_base,
rows_view& output,
CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)
)
{
return async_read_some_rows(resultset_base, 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))
CompletionToken
BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)
>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code))
async_read_some_rows(
resultset_base& resultset_base,
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_base& resultset_base, rows_view& output, error_code& err, error_info& info);
/// Reads all available rows (sync with exceptions version).
void read_all_rows(resultset_base& resultset_base, rows_view& 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_base& resultset_base,
rows_view& output,
CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)
)
{
return async_read_all_rows(resultset_base, 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_base& resultset_base,
rows_view& output,
boost::string_view stmt,
statement<Stream>& result,
error_info& output_info,
CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)
);
@@ -1074,16 +610,6 @@ public:
error_info& output_info,
CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)
);
/// Rebinds the connection type to another executor.
template <class Executor>
struct rebind_executor
{
/// The connection type when rebound to the specified executor.
using other = connection<
typename Stream:: template rebind_executor<Executor>::other
>;
};
};
/// The default TCP port for the MySQL protocol.

View File

@@ -10,7 +10,7 @@
#include <boost/mysql/error.hpp>
#include <boost/mysql/detail/channel/channel.hpp>
#include <boost/mysql/statement_base.hpp>
namespace boost {
namespace mysql {
@@ -19,7 +19,7 @@ namespace detail {
template <class Stream>
void close_statement(
channel<Stream>& chan,
std::uint32_t statement_id,
statement_base& stmt,
error_code& code,
error_info& info
);
@@ -28,7 +28,7 @@ template <class Stream, class CompletionToken>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code))
async_close_statement(
channel<Stream>& chan,
std::uint32_t statement_id,
statement_base& stmt,
CompletionToken&& token,
error_info& info
);

View File

@@ -9,6 +9,7 @@
#define BOOST_MYSQL_DETAIL_NETWORK_ALGORITHMS_EXECUTE_STATEMENT_HPP
#include <boost/mysql/error.hpp>
#include <boost/mysql/statement_base.hpp>
#include <boost/mysql/resultset_base.hpp>
#include <boost/mysql/execute_params.hpp>
#include <boost/mysql/detail/channel/channel.hpp>
@@ -20,6 +21,7 @@ namespace detail {
template <class Stream, class FieldViewFwdIterator>
void execute_statement(
channel<Stream>& channel,
const statement_base& stmt,
const execute_params<FieldViewFwdIterator>& params,
resultset_base& output,
error_code& err,
@@ -30,6 +32,7 @@ template <class Stream, class FieldViewFwdIterator, class CompletionToken>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code))
async_execute_statement(
channel<Stream>& chan,
const statement_base& stmt,
const execute_params<FieldViewFwdIterator>& params,
resultset_base& output,
error_info& info,

View File

@@ -13,22 +13,80 @@
#include <boost/mysql/detail/network_algorithms/close_statement.hpp>
#include <boost/mysql/detail/protocol/prepared_statement_messages.hpp>
namespace boost {
namespace mysql {
namespace detail {
template<class Stream>
struct close_statement_op : boost::asio::coroutine
{
channel<Stream>& chan_;
statement_base& stmt_;
close_statement_op(
channel<Stream>& chan,
statement_base& stmt
) noexcept :
chan_(chan),
stmt_(stmt)
{
}
template<class Self>
void operator()(
Self& self,
error_code err = {}
)
{
// Error checking
if (err)
{
self.complete(err);
return;
}
// Regular coroutine body; if there has been an error, we don't get here
BOOST_ASIO_CORO_REENTER(*this)
{
// Write message (already serialized at this point)
BOOST_ASIO_CORO_YIELD chan_.async_write(
chan_.shared_buffer(),
chan_.shared_sequence_number(),
std::move(self)
);
// Mark the statement as invalid
stmt_.reset();
// Complete
self.complete(error_code());
}
}
};
} // detail
} // mysql
} // boost
template <class Stream>
void boost::mysql::detail::close_statement(
channel<Stream>& chan,
std::uint32_t statement_id,
statement_base& stmt,
error_code& code,
error_info&
)
{
// Compose the close message
com_stmt_close_packet packet {statement_id};
com_stmt_close_packet packet {stmt.id()};
// Serialize it
serialize_message(packet, chan.current_capabilities(), chan.shared_buffer());
// Send it. No response is sent back
chan.write(boost::asio::buffer(chan.shared_buffer()), chan.shared_sequence_number(), code);
// Mark the statement as invalid
stmt.reset();
}
template <class Stream, class CompletionToken>
@@ -38,22 +96,22 @@ BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
)
boost::mysql::detail::async_close_statement(
channel<Stream>& chan,
std::uint32_t statement_id,
statement_base& stmt,
CompletionToken&& token,
error_info&
)
{
// Compose the close message
com_stmt_close_packet packet {statement_id};
com_stmt_close_packet packet {stmt.id()};
// Serialize it
serialize_message(packet, chan.current_capabilities(), chan.shared_buffer());
// Send it. No response is sent back
return chan.async_write(
boost::asio::buffer(chan.shared_buffer()),
chan.shared_sequence_number(),
std::forward<CompletionToken>(token)
// Trigger the async op
return boost::asio::async_compose<CompletionToken, void(error_code)>(
close_statement_op<Stream>(chan, stmt),
token,
chan
);
}

View File

@@ -48,13 +48,14 @@ public:
{
};
template <class Serializable>
template <class Serializable, class Stream>
void process_request(
const Serializable& request,
channel<Stream>& chan,
resultset_encoding encoding
)
{
output_.reset(encoding);
output_.reset(encoding, &chan);
serialize_message(request, caps_, write_buffer_);
}
@@ -236,7 +237,7 @@ void boost::mysql::detail::execute_generic(
channel.shared_buffer(),
channel.current_capabilities()
);
processor.process_request(request, encoding);
processor.process_request(request, encoding, channel);
// Send it
channel.write(channel.shared_buffer(), processor.sequence_number(), err);
@@ -296,7 +297,7 @@ boost::mysql::detail::async_execute_generic(
channel.shared_buffer(),
channel.current_capabilities()
);
processor.process_request(request, encoding);
processor.process_request(request, encoding, channel);
return boost::asio::async_compose<CompletionToken, void(error_code)>(
execute_generic_op<Stream>(channel, processor),
token,

View File

@@ -10,6 +10,7 @@
#pragma once
#include <boost/mysql/statement_base.hpp>
#include <boost/mysql/resultset_base.hpp>
#include <boost/mysql/execute_params.hpp>
#include <boost/mysql/detail/network_algorithms/execute_statement.hpp>
@@ -23,11 +24,12 @@ namespace detail {
template <class FieldViewFwdIterator>
com_stmt_execute_packet<FieldViewFwdIterator> make_stmt_execute_packet(
const execute_params<FieldViewFwdIterator>& params
const execute_params<FieldViewFwdIterator>& params,
const statement_base& stmt
)
{
return com_stmt_execute_packet<FieldViewFwdIterator> {
params.statement_id(),
stmt.id(),
std::uint8_t(0), // flags
std::uint32_t(1), // iteration count
std::uint8_t(1), // new params flag: set
@@ -44,6 +46,7 @@ com_stmt_execute_packet<FieldViewFwdIterator> make_stmt_execute_packet(
template <class Stream, class FieldViewFwdIterator>
void boost::mysql::detail::execute_statement(
channel<Stream>& chan,
const statement_base& stmt,
const execute_params<FieldViewFwdIterator>& params,
resultset_base& output,
error_code& err,
@@ -53,7 +56,7 @@ void boost::mysql::detail::execute_statement(
execute_generic(
resultset_encoding::binary,
chan,
make_stmt_execute_packet(params),
make_stmt_execute_packet(params, stmt),
output,
err,
info
@@ -67,6 +70,7 @@ BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
)
boost::mysql::detail::async_execute_statement(
channel<Stream>& chan,
const statement_base& stmt,
const execute_params<FieldViewFwdIterator>& params,
resultset_base& output,
error_info& info,
@@ -76,7 +80,7 @@ boost::mysql::detail::async_execute_statement(
return async_execute_generic(
resultset_encoding::binary,
chan,
make_stmt_execute_packet(params),
make_stmt_execute_packet(params, stmt),
output,
info,
std::forward<CompletionToken>(token)

View File

@@ -51,7 +51,7 @@ public:
serialize_message(packet, caps_, write_buffer_);
}
void process_response(boost::asio::const_buffer message, error_code& err)
void process_response(boost::asio::const_buffer message, void* channel, error_code& err)
{
deserialization_context ctx (message, caps_);
std::uint8_t msg_type = 0;
@@ -71,7 +71,7 @@ public:
{
com_stmt_prepare_ok_packet response;
err = deserialize_message(ctx, response);
output_ = statement_base(response);
output_.reset(channel, response);
remaining_meta_ = response.num_columns + response.num_params;
}
}
@@ -83,7 +83,7 @@ public:
template<class Stream>
struct prepare_statement_op : boost::asio::coroutine
{
channel<Stream> chan_;
channel<Stream>& chan_;
prepare_statement_processor processor_;
prepare_statement_op(
@@ -119,7 +119,7 @@ struct prepare_statement_op : boost::asio::coroutine
BOOST_ASIO_CORO_YIELD chan_.async_read_one(chan_.shared_sequence_number(), std::move(self));
// Process response
processor_.process_response(read_message, err);
processor_.process_response(read_message, &chan_, err);
if (err)
{
self.complete(err);
@@ -182,7 +182,7 @@ void boost::mysql::detail::prepare_statement(
return;
// Process response
processor.process_response(read_buffer, err);
processor.process_response(read_buffer, &channel, err);
if (err)
return;

View File

@@ -18,11 +18,6 @@
#include <boost/mysql/detail/network_algorithms/handshake.hpp>
#include <boost/mysql/detail/network_algorithms/execute_query.hpp>
#include <boost/mysql/detail/network_algorithms/prepare_statement.hpp>
#include <boost/mysql/detail/network_algorithms/execute_statement.hpp>
#include <boost/mysql/detail/network_algorithms/close_statement.hpp>
#include <boost/mysql/detail/network_algorithms/read_one_row.hpp>
#include <boost/mysql/detail/network_algorithms/read_some_rows.hpp>
#include <boost/mysql/detail/network_algorithms/read_all_rows.hpp>
#include <boost/mysql/detail/network_algorithms/quit_connection.hpp>
#include <boost/mysql/detail/network_algorithms/close_connection.hpp>
#include <boost/asio/buffer.hpp>
@@ -129,7 +124,7 @@ boost::mysql::connection<Stream>::async_handshake(
template <class Stream>
void boost::mysql::connection<Stream>::query(
boost::string_view query_string,
resultset_base& result,
resultset<Stream>& result,
error_code& err,
error_info& info
)
@@ -141,7 +136,7 @@ void boost::mysql::connection<Stream>::query(
template <class Stream>
void boost::mysql::connection<Stream>::query(
boost::string_view query_string,
resultset_base& result
resultset<Stream>& result
)
{
detail::error_block blk;
@@ -159,7 +154,7 @@ BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
)
boost::mysql::connection<Stream>::async_query(
boost::string_view query_string,
resultset_base& result,
resultset<Stream>& result,
error_info& output_info,
CompletionToken&& token
)
@@ -178,24 +173,24 @@ boost::mysql::connection<Stream>::async_query(
// Prepare statement
template <class Stream>
void boost::mysql::connection<Stream>::prepare_statement(
boost::string_view statement,
statement_base& output,
boost::string_view stmt,
statement<Stream>& output,
error_code& err,
error_info& info
)
{
detail::clear_errors(err, info);
detail::prepare_statement(get_channel(), statement, output, err, info);
detail::prepare_statement(get_channel(), stmt, output, err, info);
}
template <class Stream>
void boost::mysql::connection<Stream>::prepare_statement(
boost::string_view statement,
statement_base& output
boost::string_view stmt,
statement<Stream>& output
)
{
detail::error_block blk;
detail::prepare_statement(get_channel(), statement, output, blk.err, blk.info);
detail::prepare_statement(get_channel(), stmt, output, blk.err, blk.info);
blk.check();
}
@@ -208,8 +203,8 @@ BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
void(boost::mysql::error_code)
)
boost::mysql::connection<Stream>::async_prepare_statement(
boost::string_view statement,
statement_base& output,
boost::string_view stmt,
statement<Stream>& output,
error_info& output_info,
CompletionToken&& token
)
@@ -217,269 +212,7 @@ boost::mysql::connection<Stream>::async_prepare_statement(
output_info.clear();
return detail::async_prepare_statement(
get_channel(),
statement,
output,
output_info,
std::forward<CompletionToken>(token)
);
}
// Execute statement
template <class Stream>
template <class FieldViewFwdIterator>
void boost::mysql::connection<Stream>::execute_statement(
const execute_params<FieldViewFwdIterator>& params,
resultset_base& result,
error_code& err,
error_info& info
)
{
detail::clear_errors(err, info);
detail::execute_statement(
get_channel(),
params,
result,
err,
info
);
}
template <class Stream>
template <class FieldViewFwdIterator>
void boost::mysql::connection<Stream>::execute_statement(
const execute_params<FieldViewFwdIterator>& params,
resultset_base& result
)
{
detail::error_block blk;
detail::execute_statement(
get_channel(),
params,
result,
blk.err,
blk.info
);
blk.check();
}
template <class Stream>
template <class FieldViewFwdIterator, BOOST_ASIO_COMPLETION_TOKEN_FOR(
void(::boost::mysql::error_code)
) CompletionToken>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
CompletionToken,
void(boost::mysql::error_code)
)
boost::mysql::connection<Stream>::async_execute_statement(
const execute_params<FieldViewFwdIterator>& params,
resultset_base& result,
error_info& output_info,
CompletionToken&& token
)
{
output_info.clear();
detail::async_execute_statement(
get_channel(),
params,
result,
output_info,
std::forward<CompletionToken>(token)
);
}
// Close statement
template <class Stream>
void boost::mysql::connection<Stream>::close_statement(
const statement_base& stmt,
error_code& code,
error_info& info
)
{
detail::clear_errors(code, info);
detail::close_statement(get_channel(), stmt.id(), code, info);
}
template <class Stream>
void boost::mysql::connection<Stream>::close_statement(
const statement_base& stmt
)
{
detail::error_block blk;
detail::close_statement(get_channel(), stmt.id(), blk.err, blk.info);
blk.check();
}
template <class Stream>
template <BOOST_ASIO_COMPLETION_TOKEN_FOR(
void(::boost::mysql::error_code)
) CompletionToken>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
CompletionToken,
void(boost::mysql::error_code)
)
boost::mysql::connection<Stream>::async_close_statement(
const statement_base& stmt,
error_info& output_info,
CompletionToken&& token
)
{
output_info.clear();
return detail::async_close_statement(
get_channel(),
stmt.id(),
std::forward<CompletionToken>(token),
output_info
);
}
// Read one row
template <class Stream>
bool boost::mysql::connection<Stream>::read_one_row(
resultset_base& result,
row_view& output,
error_code& err,
error_info& info
)
{
detail::clear_errors(err, info);
detail::read_one_row(get_channel(), result, output, err, info);
}
template <class Stream>
bool boost::mysql::connection<Stream>::read_one_row(
resultset_base& result,
row_view& output
)
{
detail::error_block blk;
bool res = detail::read_one_row(get_channel(), result, output, blk.err, blk.info);
blk.check();
return res;
}
template <class Stream>
template <BOOST_ASIO_COMPLETION_TOKEN_FOR(
void(::boost::mysql::error_code, bool)
) CompletionToken>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
CompletionToken,
void(boost::mysql::error_code, bool)
)
boost::mysql::connection<Stream>::async_read_one_row(
resultset_base& result,
row_view& output,
error_info& output_info,
CompletionToken&& token
)
{
output_info.clear();
return detail::async_read_one_row(
get_channel(),
result,
output,
output_info,
std::forward<CompletionToken>(token)
);
}
// Read some rows
template <class Stream>
void boost::mysql::connection<Stream>::read_some_rows(
resultset_base& result,
rows_view& output,
error_code& err,
error_info& info
)
{
detail::clear_errors(err, info);
detail::read_some_rows(get_channel(), result, output, err, info);
}
template <class Stream>
void boost::mysql::connection<Stream>::read_some_rows(
resultset_base& result,
rows_view& output
)
{
detail::error_block blk;
detail::read_some_rows(get_channel(), result, output, blk.err, blk.info);
blk.check();
}
template <class Stream>
template <BOOST_ASIO_COMPLETION_TOKEN_FOR(
void(::boost::mysql::error_code)
) CompletionToken>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
CompletionToken,
void(boost::mysql::error_code)
)
boost::mysql::connection<Stream>::async_read_some_rows(
resultset_base& result,
rows_view& output,
error_info& output_info,
CompletionToken&& token
)
{
output_info.clear();
return detail::async_read_some_rows(
get_channel(),
result,
output,
output_info,
std::forward<CompletionToken>(token)
);
}
// Read all rows
template <class Stream>
void boost::mysql::connection<Stream>::read_all_rows(
resultset_base& result,
rows_view& output,
error_code& err,
error_info& info
)
{
detail::clear_errors(err, info);
detail::read_all_rows(get_channel(), result, output, err, info);
}
template <class Stream>
void boost::mysql::connection<Stream>::read_all_rows(
resultset_base& result,
rows_view& output
)
{
detail::error_block blk;
detail::read_all_rows(get_channel(), result, output, blk.err, blk.info);
blk.check();
}
template <class Stream>
template <BOOST_ASIO_COMPLETION_TOKEN_FOR(
void(::boost::mysql::error_code)
) CompletionToken>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
CompletionToken,
void(boost::mysql::error_code)
)
boost::mysql::connection<Stream>::async_read_all_rows(
resultset_base& result,
rows_view& output,
error_info& output_info,
CompletionToken&& token
)
{
output_info.clear();
return detail::async_read_all_rows(
get_channel(),
result,
stmt,
output,
output_info,
std::forward<CompletionToken>(token)

View File

@@ -0,0 +1,160 @@
//
// Copyright (c) 2019-2022 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BOOST_MYSQL_IMPL_RESULTSET_HPP
#define BOOST_MYSQL_IMPL_RESULTSET_HPP
#pragma once
#include <boost/mysql/resultset.hpp>
#include <boost/mysql/detail/network_algorithms/read_one_row.hpp>
#include <boost/mysql/detail/network_algorithms/read_some_rows.hpp>
#include <boost/mysql/detail/network_algorithms/read_all_rows.hpp>
// Read one row
template <class Stream>
bool boost::mysql::resultset<Stream>::read_one(
row_view& output,
error_code& err,
error_info& info
)
{
detail::clear_errors(err, info);
detail::read_one_row(get_channel(), *this, output, err, info);
}
template <class Stream>
bool boost::mysql::resultset<Stream>::read_one(
row_view& output
)
{
detail::error_block blk;
bool res = detail::read_one_row(get_channel(), *this, output, blk.err, blk.info);
blk.check();
return res;
}
template <class Stream>
template <BOOST_ASIO_COMPLETION_TOKEN_FOR(
void(::boost::mysql::error_code, bool)
) CompletionToken>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
CompletionToken,
void(boost::mysql::error_code, bool)
)
boost::mysql::resultset<Stream>::async_read_one(
row_view& output,
error_info& output_info,
CompletionToken&& token
)
{
output_info.clear();
return detail::async_read_one_row(
get_channel(),
*this,
output,
output_info,
std::forward<CompletionToken>(token)
);
}
// Read some rows
template <class Stream>
void boost::mysql::resultset<Stream>::read_some(
rows_view& output,
error_code& err,
error_info& info
)
{
detail::clear_errors(err, info);
detail::read_some_rows(get_channel(), *this, output, err, info);
}
template <class Stream>
void boost::mysql::resultset<Stream>::read_some(
rows_view& output
)
{
detail::error_block blk;
detail::read_some_rows(get_channel(), *this, output, blk.err, blk.info);
blk.check();
}
template <class Stream>
template <BOOST_ASIO_COMPLETION_TOKEN_FOR(
void(::boost::mysql::error_code)
) CompletionToken>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
CompletionToken,
void(boost::mysql::error_code)
)
boost::mysql::resultset<Stream>::async_read_some(
rows_view& output,
error_info& output_info,
CompletionToken&& token
)
{
output_info.clear();
return detail::async_read_some_rows(
get_channel(),
*this,
output,
output_info,
std::forward<CompletionToken>(token)
);
}
// Read all rows
template <class Stream>
void boost::mysql::resultset<Stream>::read_all(
rows_view& output,
error_code& err,
error_info& info
)
{
detail::clear_errors(err, info);
detail::read_all_rows(get_channel(), *this, output, err, info);
}
template <class Stream>
void boost::mysql::resultset<Stream>::read_all(
rows_view& output
)
{
detail::error_block blk;
detail::read_all_rows(get_channel(), *this, output, blk.err, blk.info);
blk.check();
}
template <class Stream>
template <BOOST_ASIO_COMPLETION_TOKEN_FOR(
void(::boost::mysql::error_code)
) CompletionToken>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
CompletionToken,
void(boost::mysql::error_code)
)
boost::mysql::resultset<Stream>::async_read_all(
rows_view& output,
error_info& output_info,
CompletionToken&& token
)
{
output_info.clear();
return detail::async_read_all_rows(
get_channel(),
*this,
output,
output_info,
std::forward<CompletionToken>(token)
);
}
#endif

View File

@@ -0,0 +1,128 @@
//
// Copyright (c) 2019-2022 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BOOST_MYSQL_IMPL_STATEMENT_HPP
#define BOOST_MYSQL_IMPL_STATEMENT_HPP
#pragma once
#include <boost/mysql/statement.hpp>
#include <boost/mysql/detail/network_algorithms/execute_statement.hpp>
#include <boost/mysql/detail/network_algorithms/close_statement.hpp>
// Execute statement
template <class Stream>
template <class FieldViewFwdIterator>
void boost::mysql::statement<Stream>::execute(
const execute_params<FieldViewFwdIterator>& params,
resultset<Stream>& result,
error_code& err,
error_info& info
)
{
detail::clear_errors(err, info);
detail::execute_statement(
get_channel(),
*this,
params,
result,
err,
info
);
}
template <class Stream>
template <class FieldViewFwdIterator>
void boost::mysql::statement<Stream>::execute(
const execute_params<FieldViewFwdIterator>& params,
resultset<Stream>& result
)
{
detail::error_block blk;
detail::execute_statement(
get_channel(),
*this,
params,
result,
blk.err,
blk.info
);
blk.check();
}
template <class Stream>
template <class FieldViewFwdIterator, BOOST_ASIO_COMPLETION_TOKEN_FOR(
void(::boost::mysql::error_code)
) CompletionToken>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
CompletionToken,
void(boost::mysql::error_code)
)
boost::mysql::statement<Stream>::async_execute(
const execute_params<FieldViewFwdIterator>& params,
resultset<Stream>& result,
error_info& output_info,
CompletionToken&& token
)
{
output_info.clear();
detail::async_execute_statement(
get_channel(),
*this,
params,
result,
output_info,
std::forward<CompletionToken>(token)
);
}
// Close statement
template <class Stream>
void boost::mysql::statement<Stream>::close(
error_code& code,
error_info& info
)
{
detail::clear_errors(code, info);
detail::close_statement(get_channel(), *this, code, info);
}
template <class Stream>
void boost::mysql::statement<Stream>::close()
{
detail::error_block blk;
detail::close_statement(get_channel(), *this, blk.err, blk.info);
blk.check();
}
template <class Stream>
template <BOOST_ASIO_COMPLETION_TOKEN_FOR(
void(::boost::mysql::error_code)
) CompletionToken>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
CompletionToken,
void(boost::mysql::error_code)
)
boost::mysql::statement<Stream>::async_close(
error_info& output_info,
CompletionToken&& token
)
{
output_info.clear();
return detail::async_close_statement(
get_channel(),
*this,
std::forward<CompletionToken>(token),
output_info
);
}
#endif

View File

@@ -0,0 +1,221 @@
//
// Copyright (c) 2019-2022 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BOOST_MYSQL_RESULTSET_HPP
#define BOOST_MYSQL_RESULTSET_HPP
#include <boost/mysql/detail/channel/channel.hpp>
#include <boost/mysql/resultset_base.hpp>
#include <boost/mysql/row_view.hpp>
#include <boost/mysql/rows_view.hpp>
#include <boost/asio/async_result.hpp>
#include <cassert>
namespace boost {
namespace mysql {
template <class Stream>
class resultset : public resultset_base
{
public:
resultset() = default;
resultset(const resultset&) = delete;
resultset(resultset&& other) noexcept : resultset_base(std::move(other)) { other.reset(); }
resultset& operator=(const resultset&) = delete;
resultset& operator=(resultset&& rhs) noexcept { swap(rhs); rhs.reset(); return *this; }
~resultset() = default;
using executor_type = typename Stream::executor_type;
executor_type get_executor() { return get_channel().get_executor(); }
/**
* \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_base 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_view& 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_base 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_view& 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_base 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_view& output,
CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)
)
{
return async_read_one(output, get_channel().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_base 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_view& output,
error_info& output_info,
CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)
);
void read_some(rows_view& output, error_code& err, error_info& info);
void read_some(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))
CompletionToken
BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)
>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code))
async_read_some(
rows_view& output,
CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)
)
{
return async_read_some(output, get_channel().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))
CompletionToken
BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)
>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code))
async_read_some(
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_view& output, error_code& err, error_info& info);
/// Reads all available rows (sync with exceptions version).
void read_all(rows_view& 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_view& output,
CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)
)
{
return async_read_all(output, get_channel().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_view& output,
error_info& output_info,
CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)
);
private:
detail::channel<Stream>& get_channel() noexcept
{
assert(valid());
return *static_cast<detail::channel<Stream>*>(channel_ptr());
}
};
} // mysql
} // boost
#include <boost/mysql/impl/resultset.hpp>
#endif

View File

@@ -71,7 +71,7 @@ class resultset_base
boost::string_view info() const noexcept { assert(has_data_); return info_; }
};
bool valid_ {false};
void* channel_ {nullptr};
std::uint8_t seqnum_ {};
detail::resultset_encoding encoding_ { detail::resultset_encoding::text };
std::vector<metadata> meta_;
@@ -84,23 +84,12 @@ public:
#ifndef BOOST_MYSQL_DOXYGEN
// Private, do not use. TODO: hide these
resultset_base(std::vector<metadata>&& meta, detail::resultset_encoding encoding) noexcept:
valid_(true),
encoding_(encoding),
meta_(std::move(meta))
{
};
resultset_base(const detail::ok_packet& ok_pack):
valid_(true),
ok_packet_(ok_pack)
{
};
void reset(
void* channel,
detail::resultset_encoding encoding
)
) noexcept
{
valid_ = true;
channel_ = channel;
seqnum_ = 0;
encoding_ = encoding;
meta_.clear();
@@ -109,7 +98,7 @@ public:
void complete(const detail::ok_packet& ok_pack)
{
assert(valid_);
assert(valid());
ok_packet_.assign(ok_pack);
}
@@ -137,7 +126,7 @@ public:
* Calling any member function on an invalid resultset_base,
* other than assignment, results in undefined behavior.
*/
bool valid() const noexcept { return valid_; }
bool valid() const noexcept { return channel_ != nullptr; }
/// \brief Returns whether the resultset_base has been completely read or not.
/// \details See [link mysql.resultsets.complete this section] for more info.
@@ -179,6 +168,10 @@ public:
* until the resultset_base object is destroyed.
*/
boost::string_view info() const noexcept { return ok_packet_.info(); }
protected:
void* channel_ptr() noexcept { return channel_; }
void reset() noexcept { reset(nullptr, detail::resultset_encoding::text); }
void swap(resultset_base& other) noexcept { std::swap(*this, other); }
};
} // mysql

View File

@@ -0,0 +1,327 @@
//
// Copyright (c) 2019-2022 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BOOST_MYSQL_STATEMENT_HPP
#define BOOST_MYSQL_STATEMENT_HPP
#include <boost/mysql/detail/channel/channel.hpp>
#include <boost/mysql/detail/auxiliar/field_type_traits.hpp>
#include <boost/mysql/statement_base.hpp>
#include <boost/mysql/resultset.hpp>
#include <boost/mysql/execute_params.hpp>
#include <cassert>
namespace boost {
namespace mysql {
template <class Stream>
class statement : public statement_base
{
public:
statement() = default;
statement(const statement&) = delete;
statement(statement&& other) noexcept : statement_base(other) { other.reset(); }
statement& operator=(const statement&) = delete;
statement& operator=(statement&& rhs) noexcept { swap(std::move(rhs)); return *this; }
~statement() = default;
using executor_type = typename Stream::executor_type;
executor_type get_executor() { return get_channel().get_executor(); }
/**
* \brief Executes a statement (collection, sync with error code version).
* \details
* FieldViewCollection should meet the [reflink FieldViewCollection] requirements.
*
* After this function has returned, you should read the entire resultset_base
* before calling any function that involves communication with the server over this
* connection. Otherwise, the results are undefined.
*/
template <class FieldViewCollection, class EnableIf = detail::enable_if_field_view_collection<FieldViewCollection>>
void execute(
const FieldViewCollection& params,
resultset<Stream>& result,
error_code& err,
error_info& info
)
{
return execute(make_execute_params(params), result, err, info);
}
/**
* \brief Executes a statement (collection, sync with exceptions version).
* \details
* FieldViewCollection should meet the [reflink FieldViewCollection] requirements.
*
* After this function has returned, you should read the entire resultset_base
* before calling any function that involves communication with the server over this
* connection. Otherwise, the results are undefined.
*/
template <class FieldViewCollection, class EnableIf = detail::enable_if_field_view_collection<FieldViewCollection>>
void execute(
const FieldViewCollection& params,
resultset<Stream>& result
)
{
return execute_statement(make_execute_params(params), result);
}
/**
* \brief Executes a statement (collection,
* async without [reflink error_info] version).
* \details
* FieldViewCollection should meet the [reflink FieldViewCollection] requirements.
*
* After this operation completes, you should read the entire resultset_base
* 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_base<Stream>)`.
*/
template<
class FieldViewCollection,
BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))
CompletionToken
BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type),
class EnableIf = detail::enable_if_field_view_collection<FieldViewCollection>
>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code))
async_execute(
const FieldViewCollection& params,
resultset<Stream>& result,
CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)
)
{
return async_execute_statement(
make_execute_params(params),
result,
std::forward<CompletionToken>(token)
);
}
/**
* \brief Executes a statement (collection,
* async with [reflink error_info] version).
* \details
* FieldViewCollection should meet the [reflink FieldViewCollection] requirements.
*
* After this operation completes, you should read the entire resultset_base
* 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_base<Stream>)`.
*/
template <
class FieldViewCollection,
BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))
CompletionToken
BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type),
class EnableIf = detail::enable_if_field_view_collection<FieldViewCollection>
>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code))
async_execute(
const FieldViewCollection& params,
resultset<Stream>& result,
error_info& output_info,
CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)
)
{
return async_execute_statement(
make_execute_params(params),
result,
output_info,
std::forward<CompletionToken>(token)
);
}
/**
* \brief Executes a statement (`execute_params`, sync with error code version).
* \details
* FieldViewFwdIterator should meet the [reflink FieldViewFwdIterator] 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_base
* before calling any function that involves communication with the server over this
* connection. Otherwise, the results are undefined.
*/
template <class FieldViewFwdIterator>
void execute(
const execute_params<FieldViewFwdIterator>& params,
resultset<Stream>& result,
error_code& ec,
error_info& info
);
/**
* \brief Executes a statement (`execute_params`, sync with exceptions version).
* \details
* FieldViewFwdIterator should meet the [reflink FieldViewFwdIterator] 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_base
* before calling any function that involves communication with the server over this
* connection. Otherwise, the results are undefined.
*/
template <class FieldViewFwdIterator>
void execute(
const execute_params<FieldViewFwdIterator>& params,
resultset<Stream>& result
);
/**
* \brief Executes a statement (`execute_params`,
* async without [reflink error_info] version).
* \details
* FieldViewFwdIterator should meet the [reflink FieldViewFwdIterator] 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_base
* 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_base<Stream>)`.
*/
template <
class FieldViewFwdIterator,
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(
const execute_params<FieldViewFwdIterator>& params,
resultset<Stream>& result,
CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)
)
{
return async_execute(params, result, get_channel().shared_info(), std::forward<CompletionToken>(token));
}
/**
* \brief Executes a statement (`execute_params`,
* async with [reflink error_info] version).
* \details
* FieldViewFwdIterator should meet the [reflink FieldViewFwdIterator] 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_base
* 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_base<Stream>)`.
*/
template <
class FieldViewFwdIterator,
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(
const execute_params<FieldViewFwdIterator>& params,
resultset<Stream>& 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(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(get_channel().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)
);
private:
detail::channel<Stream>& get_channel() noexcept
{
assert(valid());
return *static_cast<detail::channel<Stream>*>(channel_ptr());
}
};
} // mysql
} // boost
#include <boost/mysql/impl/statement.hpp>
#endif

View File

@@ -41,8 +41,6 @@ constexpr std::array<field_view, 0> no_statement_params {};
*/
class statement_base
{
bool valid_ {false};
detail::com_stmt_prepare_ok_packet stmt_msg_;
public:
/**
* \brief Default constructor.
@@ -52,8 +50,16 @@ public:
#ifndef BOOST_MYSQL_DOXYGEN
// Private. Do not use. TODO: hide this
statement_base(const detail::com_stmt_prepare_ok_packet& msg) noexcept:
valid_(true), stmt_msg_(msg) {}
void reset(
void* channel,
const detail::com_stmt_prepare_ok_packet& msg
) noexcept
{
channel_ = channel;
stmt_msg_ = msg;
}
void reset() noexcept { channel_ = nullptr; }
#endif
/**
@@ -61,7 +67,7 @@ public:
* \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 valid_; }
bool valid() const noexcept { return channel_ != nullptr; }
/// Returns a server-side identifier for the statement (unique in a per-connection basis).
std::uint32_t id() const noexcept { assert(valid()); return stmt_msg_.statement_id; }
@@ -69,6 +75,12 @@ public:
/// 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; }
protected:
void* channel_ptr() noexcept { return channel_; }
void swap(statement_base& other) noexcept { std::swap(*this, other); }
private:
void* channel_ {nullptr};
detail::com_stmt_prepare_ok_packet stmt_msg_;
};
} // mysql

View File

@@ -17,6 +17,9 @@ namespace mysql {
/// A connection to MySQL over a TCP socket.
using tcp_connection = connection<boost::asio::ip::tcp::socket>;
using tcp_statement = typename tcp_connection::statement_type;
using tcp_resultset = typename tcp_connection::resultset_type;
} // mysql
} // boost

View File

@@ -17,6 +17,8 @@ namespace mysql {
/// A connection to MySQL over a TCP socket using TLS.
using tcp_ssl_connection = connection<boost::asio::ssl::stream<boost::asio::ip::tcp::socket>>;
using tcp_ssl_statement = typename tcp_ssl_connection::statement_type;
using tcp_ssl_resultset = typename tcp_ssl_connection::resultset_type;
} // mysql
} // boost

View File

@@ -18,6 +18,8 @@ namespace mysql {
/// A connection to MySQL over a UNIX domain socket.
using unix_connection = connection<boost::asio::local::stream_protocol::socket>;
using unix_statement = typename unix_connection::statement_type;
using unix_resultset = typename unix_connection::resultset_type;
#endif

View File

@@ -19,6 +19,8 @@ namespace mysql {
/// A connection to MySQL over a UNIX domain socket over TLS.
using unix_ssl_connection = connection<boost::asio::ssl::stream<boost::asio::local::stream_protocol::socket>>;
using unix_ssl_statement = typename unix_ssl_connection::statement_type;
using unix_ssl_resultset = typename unix_ssl_connection::resultset_type;
#endif