2
0
mirror of https://github.com/boostorg/mysql.git synced 2026-02-15 01:02:17 +00:00
Files
mysql/include/mysql/resultset.hpp
2020-01-18 20:05:21 +00:00

183 lines
6.9 KiB
C++

#ifndef MYSQL_ASIO_RESULTSET_HPP
#define MYSQL_ASIO_RESULTSET_HPP
#include "mysql/row.hpp"
#include "mysql/metadata.hpp"
#include "mysql/impl/messages.hpp"
#include "mysql/impl/channel.hpp"
#include <boost/asio/ip/tcp.hpp>
#include <cassert>
namespace mysql
{
/**
* \brief Represents tabular data retrieved from the MySQL server.
* \details Returned as the result of a query (\see connection::query).
*
* A resultset does not read all the retrieved information into memory
* directly. Instead, you use fetch_one, fetch_many
* or fetch_all to load rows progressively. This allows for better efficiency.
*
* A resultset can be in two states:
* - Complete, meaning that all data has already been retrieved for this
* resultset.
* - Not complete, meaning that there is still rows to be read.
*
* You can test whether a resultset is complete or not by calling
* resultset::complete().
*
* Resultsets also contain metadata about the fields in the query.
* You can access them at any point using resultset::fields().
*
* The result of a SQL statement that does not return any data (e.g.
* an UPDATE statement) is an empty resultset. An empty resultset
* is complete since the very beginning, and fields() will be empty.
*
* Resultsets contain additional data about the execution of the query,
* like the warning count or the last insert ID. You may access this information
* **only after the resultset is complete**. Failing to do so results
* in undefined behavior.
*
* Resultsets are default-constructible. A default-constructed resultset has
* valid() == false. It is undefined to call any member function on an invalid
* resultset, other than assignment. Resultsets are movable but not copyable.
*/
template <
typename StreamType
>
class resultset
{
using channel_type = detail::channel<StreamType>;
channel_type* channel_;
detail::resultset_metadata meta_;
row current_row_;
detail::bytestring buffer_;
detail::ok_packet ok_packet_;
bool eof_received_ {false};
public:
/// Default constructor.
resultset(): channel_(nullptr) {};
// Private, do not use
resultset(channel_type& channel, detail::resultset_metadata&& meta):
channel_(&channel), meta_(std::move(meta)) {};
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) {};
/**
* \brief Fetches a single row (sync with error code version).
* \details The returned object will be nullptr if there are no more rows
* to be read. Calling fetch_one on a complete resultset returns nullptr.
*
* The returned row points into memory owned by the resultset. Destroying
* or moving the resultset object invalidates the returned row. Calling
* any of the fetch methods again does also invalidate the returned row.
* fetch_one is the fetch method that performs the less memory allocations
* of the three.
*/
const row* fetch_one(error_code& err, error_info& info);
/// Fetches a single row (sync with exceptions version).
const row* fetch_one();
/**
* \brief Fetches at most count rows (sync with error code version).
* \details The returned rows are guaranteed to be valid as long as the
* resultset is alive. Contrary to fetch_one, subsequent calls to any of
* the fetch methods do not invalidate the returned rows.
*
* Only if count is **greater** than the available number of rows,
* the resultset will be completed.
*/
std::vector<owning_row> fetch_many(std::size_t count, error_code& err, error_info& info);
/// Fetches at most count rows (sync with exceptions version).
std::vector<owning_row> fetch_many(std::size_t count);
/**
* \brief Fetches all available rows (sync with error code version).
* \details The returned rows are guaranteed to be valid as long as the
* resultset is alive. Contrary to fetch_one, subsequent calls to any of
* the fetch methods do not invalidate the returned rows.
*
* The resultset is guaranteed to be complete() after this call returns.
*/
std::vector<owning_row> fetch_all(error_code& err, error_info& info);
/// Fetches all available rows (sync with exceptions version).
std::vector<owning_row> fetch_all();
/// Fetchs a single row (async version).
template <typename CompletionToken>
BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void(error_code, error_info, const row*))
async_fetch_one(CompletionToken&& token);
/// Fetches at most count rows (async version).
template <typename CompletionToken>
BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void(error_code, error_info, std::vector<owning_row>))
async_fetch_many(std::size_t count, CompletionToken&& token);
/// Fetches all available rows (async version).
template <typename CompletionToken>
BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void(error_code, error_info, std::vector<owning_row>))
async_fetch_all(CompletionToken&& token);
/**
* \brief Returns whether this object represents a valid resultset.
* \details Returns false for default-constructed resultsets. It is
* undefined to call any member function on an invalid resultset,
* except assignment.
*/
bool valid() const noexcept { return channel_ != nullptr; }
/// Returns whether the resultset has been completely read or not.
bool complete() const noexcept { return eof_received_; }
/**
* \brief Returns metadata about the fields in the query.
* \details There will be as many field_metadata objects as fields
* in the SQL query, and in the same order. For SQL statements
* that do not return values (like UPDATEs), it will be empty.
* \see field_metadata for more details.
*/
const std::vector<field_metadata>& fields() const noexcept { return meta_.fields(); }
/**
* \brief The number of rows affected by the SQL that generated this resultset.
* \warning The resultset **must be complete** before calling this function.
*/
std::uint64_t affected_rows() const noexcept { assert(complete()); return ok_packet_.affected_rows.value; }
/**
* \brief The last insert ID produced by the SQL that generated this resultset.
* \warning The resultset **must be complete** before calling this function.
*/
std::uint64_t last_insert_id() const noexcept { assert(complete()); return ok_packet_.last_insert_id.value; }
/**
* \brief The number of warnings produced by the SQL that generated this resultset.
* \warning The resultset **must be complete** before calling this function.
*/
unsigned warning_count() const noexcept { assert(complete()); return ok_packet_.warnings.value; }
/**
* \brief Additionat text information about the execution of
* the SQL that generated this resultset.
* \warning The resultset **must be complete** before calling this function.
*/
std::string_view info() const noexcept { assert(complete()); return ok_packet_.info.value; }
// TODO: status flags accessors
};
/// Specialization of resultset for TCP sockets.
using tcp_resultset = resultset<boost::asio::ip::tcp::socket>;
}
#include "mysql/impl/resultset.ipp"
#endif