mirror of
https://github.com/boostorg/mysql.git
synced 2026-02-14 00:42:53 +00:00
Added error_info
This commit is contained in:
65
.travis.yml
65
.travis.yml
@@ -8,6 +8,53 @@ matrix:
|
||||
compiler: gcc
|
||||
services:
|
||||
- mysql
|
||||
env:
|
||||
- CMAKE_OPTIONS=-DCMAKE_BUILD_TYPE=Debug
|
||||
addons:
|
||||
apt:
|
||||
update: true
|
||||
sources:
|
||||
- sourceline: 'ppa:mhier/libboost-latest'
|
||||
packages:
|
||||
- boost1.70
|
||||
- os: linux
|
||||
dist: bionic
|
||||
sudo: true
|
||||
compiler: gcc
|
||||
services:
|
||||
- mysql
|
||||
env:
|
||||
- CMAKE_OPTIONS=-DCMAKE_BUILD_TYPE=Release
|
||||
addons:
|
||||
apt:
|
||||
update: true
|
||||
sources:
|
||||
- sourceline: 'ppa:mhier/libboost-latest'
|
||||
packages:
|
||||
- boost1.70
|
||||
- os: linux
|
||||
dist: bionic
|
||||
sudo: true
|
||||
compiler: gcc
|
||||
services:
|
||||
- mysql
|
||||
env:
|
||||
- CMAKE_OPTIONS=-DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++
|
||||
addons:
|
||||
apt:
|
||||
update: true
|
||||
sources:
|
||||
- sourceline: 'ppa:mhier/libboost-latest'
|
||||
packages:
|
||||
- boost1.70
|
||||
- os: linux
|
||||
dist: bionic
|
||||
sudo: true
|
||||
compiler: gcc
|
||||
services:
|
||||
- mysql
|
||||
env:
|
||||
- CMAKE_OPTIONS=-DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++
|
||||
addons:
|
||||
apt:
|
||||
update: true
|
||||
@@ -27,12 +74,24 @@ matrix:
|
||||
before_install:
|
||||
- mysql.server start
|
||||
env:
|
||||
- CMAKE_OPTIONS=-DOPENSSL_ROOT_DIR=/usr/local/opt/openssl
|
||||
|
||||
- CMAKE_OPTIONS=-DOPENSSL_ROOT_DIR=/usr/local/opt/openssl -DCMAKE_BUILD_TYPE=Debug
|
||||
- os: osx
|
||||
osx_image: xcode11.3
|
||||
sudo: true
|
||||
compiler: clang
|
||||
addons:
|
||||
homebrew:
|
||||
packages:
|
||||
- boost
|
||||
- mysql
|
||||
before_install:
|
||||
- mysql.server start
|
||||
env:
|
||||
- CMAKE_OPTIONS=-DOPENSSL_ROOT_DIR=/usr/local/opt/openssl -DCMAKE_BUILD_TYPE=Release
|
||||
|
||||
script:
|
||||
- mkdir -p build
|
||||
- cd build
|
||||
- cmake -DCMAKE_BUILD_TYPE=Release $CMAKE_OPTIONS ..
|
||||
- cmake $CMAKE_OPTIONS ..
|
||||
- make -j CTEST_OUTPUT_ON_FAILURE=1 all test
|
||||
|
||||
|
||||
14
TODO.txt
14
TODO.txt
@@ -1,3 +1,14 @@
|
||||
error_info
|
||||
Add error_info to all existing API
|
||||
Document
|
||||
Add error_info to examples
|
||||
Add error_info to integ tests
|
||||
Make error_info optional for synchronous (?)
|
||||
Use error_info in sync exc
|
||||
Add validation of exception messages
|
||||
Error code descriptions
|
||||
Review async testing with futures (it no longer tests the error_info parameter)
|
||||
Verify that error_codes are cleared in sync errc stuff
|
||||
Prepared statements
|
||||
Multiresultset
|
||||
Text protocol
|
||||
@@ -9,9 +20,6 @@ Handshake
|
||||
Usability
|
||||
Incomplete query reads: how does this affect further queries?
|
||||
Metadata in rows: being able to index by name
|
||||
Errors
|
||||
Error code descriptions
|
||||
Error text is lost in the protocol
|
||||
Iterators for sync resultset iteration
|
||||
Better interface for connection_params data structure
|
||||
Consideration of timezones
|
||||
|
||||
@@ -27,11 +27,11 @@ void print_employee(const mysql::row& employee)
|
||||
<< employee.values()[2] << " dollars yearly\n"; // salary (type double)
|
||||
}
|
||||
|
||||
void die_on_error(const mysql::error_code& err)
|
||||
void die_on_error(const mysql::error_code& err, const mysql::error_info& info = mysql::error_info())
|
||||
{
|
||||
if (err)
|
||||
{
|
||||
std::cerr << "Error: " << err << std::endl;
|
||||
std::cerr << "Error: " << err << ": " << info.message() << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
@@ -55,10 +55,10 @@ public:
|
||||
|
||||
void connect()
|
||||
{
|
||||
connection.next_level().async_connect(ep, [this](const mysql::error_code& err) {
|
||||
connection.next_level().async_connect(ep, [this](mysql::error_code err) {
|
||||
die_on_error(err);
|
||||
connection.async_handshake(conn_params, [this](const mysql::error_code& err) {
|
||||
die_on_error(err);
|
||||
connection.async_handshake(conn_params, [this](mysql::error_code err, const mysql::error_info& info) {
|
||||
die_on_error(err, info);
|
||||
query_employees();
|
||||
});
|
||||
});
|
||||
@@ -67,11 +67,13 @@ public:
|
||||
void query_employees()
|
||||
{
|
||||
const char* sql = "SELECT first_name, last_name, salary FROM employee WHERE company_id = 'HGS'";
|
||||
connection.async_query(sql, [this](const mysql::error_code& err, mysql::tcp_resultset&& result) {
|
||||
die_on_error(err);
|
||||
connection.async_query(sql, [this](mysql::error_code err, const mysql::error_info& info,
|
||||
mysql::tcp_resultset&& result
|
||||
) {
|
||||
die_on_error(err, info);
|
||||
resultset = std::move(result);
|
||||
resultset.async_fetch_all([this](const mysql::error_code& err, const auto& rows) {
|
||||
die_on_error(err);
|
||||
resultset.async_fetch_all([this](mysql::error_code err, const mysql::error_info& info, const auto& rows) {
|
||||
die_on_error(err, info);
|
||||
for (const auto& employee: rows)
|
||||
{
|
||||
print_employee(employee);
|
||||
@@ -84,8 +86,9 @@ public:
|
||||
void update_slacker()
|
||||
{
|
||||
const char* sql = "UPDATE employee SET salary = 15000 WHERE last_name = 'Slacker'";
|
||||
connection.async_query(sql, [this](const mysql::error_code& err, [[maybe_unused]] mysql::tcp_resultset&& result) {
|
||||
die_on_error(err);
|
||||
connection.async_query(sql, [this](mysql::error_code err, const mysql::error_info& info,
|
||||
[[maybe_unused]] mysql::tcp_resultset&& result) {
|
||||
die_on_error(err, info);
|
||||
assert(result.fields().size() == 0);
|
||||
query_intern();
|
||||
});
|
||||
@@ -94,11 +97,12 @@ public:
|
||||
void query_intern()
|
||||
{
|
||||
const char* sql = "SELECT salary FROM employee WHERE last_name = 'Slacker'";
|
||||
connection.async_query(sql, [this](const mysql::error_code& err, mysql::tcp_resultset&& result) {
|
||||
die_on_error(err);
|
||||
connection.async_query(sql, [this](const mysql::error_code& err, mysql::error_info info,
|
||||
mysql::tcp_resultset&& result) {
|
||||
die_on_error(err, info);
|
||||
resultset = std::move(result);
|
||||
resultset.async_fetch_all([](const mysql::error_code& err, const auto& rows) {
|
||||
die_on_error(err);
|
||||
resultset.async_fetch_all([](const mysql::error_code& err, mysql::error_info info, const auto& rows) {
|
||||
die_on_error(err, info);
|
||||
assert(rows.size() == 1);
|
||||
[[maybe_unused]] auto salary = std::get<double>(rows[0].values()[0]);
|
||||
assert(salary == 15000);
|
||||
|
||||
@@ -85,7 +85,7 @@ public:
|
||||
const Stream& next_level() const { return next_level_; }
|
||||
|
||||
/// Performs the MySQL-level handshake (synchronous with error code version).
|
||||
void handshake(const connection_params& params, error_code& ec);
|
||||
void handshake(const connection_params& params, error_code& ec, error_info& info);
|
||||
|
||||
/// Performs the MySQL-level handshake (synchronous with exceptions version).
|
||||
void handshake(const connection_params& params);
|
||||
@@ -96,7 +96,7 @@ public:
|
||||
* until the operation completes, as no copy is made by the library.
|
||||
*/
|
||||
template <typename CompletionToken>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void(error_code))
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void(error_code, error_info))
|
||||
async_handshake(const connection_params& params, CompletionToken&& token);
|
||||
|
||||
/**
|
||||
@@ -111,14 +111,14 @@ public:
|
||||
* \warning After query() has returned, you should read the entire resultset
|
||||
* before calling query() again. Otherwise, the results are undefined.
|
||||
*/
|
||||
resultset<Stream> query(std::string_view query_string, error_code&);
|
||||
resultset<Stream> query(std::string_view query_string, error_code&, error_info&);
|
||||
|
||||
/// Executes a SQL text query (sync with exceptions version).
|
||||
resultset<Stream> query(std::string_view query_string);
|
||||
|
||||
/// Executes a SQL text query (async version).
|
||||
template <typename CompletionToken>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void(error_code, resultset<Stream>))
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void(error_code, error_info, resultset<Stream>))
|
||||
async_query(std::string_view query_string, CompletionToken&& token);
|
||||
};
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define MYSQL_ASIO_ERROR_HPP
|
||||
|
||||
#include <boost/system/error_code.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace mysql
|
||||
{
|
||||
@@ -27,6 +28,20 @@ enum class Error : int
|
||||
/// An alias for boost::system error codes.
|
||||
using error_code = boost::system::error_code;
|
||||
|
||||
/// Additional information about error conditions
|
||||
class error_info
|
||||
{
|
||||
std::string msg_;
|
||||
public:
|
||||
error_info(std::string&& err = {}): msg_(std::move(err)) {}
|
||||
const std::string& message() const noexcept { return msg_; }
|
||||
void set_message(std::string&& err) { msg_ = std::move(err); }
|
||||
void clear() noexcept { msg_.clear(); }
|
||||
};
|
||||
inline bool operator==(const error_info& lhs, const error_info& rhs) noexcept { return lhs.message() == rhs.message(); }
|
||||
inline bool operator!=(const error_info& lhs, const error_info& rhs) noexcept { return !(lhs==rhs); }
|
||||
inline std::ostream& operator<<(std::ostream& os, const error_info& v) { return os << v.message(); }
|
||||
|
||||
}
|
||||
|
||||
#include "mysql/impl/error.hpp"
|
||||
|
||||
@@ -28,10 +28,19 @@ inline handshake_params to_handshake_params(
|
||||
template <typename Stream>
|
||||
void mysql::connection<Stream>::handshake(
|
||||
const connection_params& params,
|
||||
error_code& errc
|
||||
error_code& errc,
|
||||
error_info& info
|
||||
)
|
||||
{
|
||||
detail::hanshake(channel_, detail::to_handshake_params(params), buffer_, errc);
|
||||
errc.clear();
|
||||
info.clear();
|
||||
detail::hanshake(
|
||||
channel_,
|
||||
detail::to_handshake_params(params),
|
||||
buffer_,
|
||||
errc,
|
||||
info
|
||||
);
|
||||
// TODO: should we close() the stream in case of error?
|
||||
}
|
||||
|
||||
@@ -41,13 +50,14 @@ void mysql::connection<Stream>::handshake(
|
||||
)
|
||||
{
|
||||
error_code errc;
|
||||
handshake(params, errc);
|
||||
detail::check_error_code(errc);
|
||||
error_info info;
|
||||
handshake(params, errc, info);
|
||||
detail::check_error_code(errc, info);
|
||||
}
|
||||
|
||||
template <typename Stream>
|
||||
template <typename CompletionToken>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void(mysql::error_code))
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void(mysql::error_code, mysql::error_info))
|
||||
mysql::connection<Stream>::async_handshake(
|
||||
const connection_params& params,
|
||||
CompletionToken&& token
|
||||
@@ -65,11 +75,14 @@ mysql::connection<Stream>::async_handshake(
|
||||
template <typename Stream>
|
||||
mysql::resultset<Stream> mysql::connection<Stream>::query(
|
||||
std::string_view query_string,
|
||||
error_code& err
|
||||
error_code& err,
|
||||
error_info& info
|
||||
)
|
||||
{
|
||||
err.clear();
|
||||
info.clear();
|
||||
resultset<Stream> res;
|
||||
detail::execute_query(channel_, query_string, res, err);
|
||||
detail::execute_query(channel_, query_string, res, err, info);
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -80,14 +93,18 @@ mysql::resultset<Stream> mysql::connection<Stream>::query(
|
||||
{
|
||||
resultset<Stream> res;
|
||||
error_code err;
|
||||
detail::execute_query(channel_, query_string, res, err);
|
||||
detail::check_error_code(err);
|
||||
error_info info;
|
||||
detail::execute_query(channel_, query_string, res, err, info);
|
||||
detail::check_error_code(err, info);
|
||||
return res;
|
||||
}
|
||||
|
||||
template <typename Stream>
|
||||
template <typename CompletionToken>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void(mysql::error_code, mysql::resultset<Stream>))
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(
|
||||
CompletionToken,
|
||||
void(mysql::error_code, mysql::error_info, mysql::resultset<Stream>)
|
||||
)
|
||||
mysql::connection<Stream>::async_query(
|
||||
std::string_view query_string,
|
||||
CompletionToken&& token
|
||||
|
||||
@@ -64,11 +64,11 @@ inline boost::system::error_code make_error_code(Error error)
|
||||
);
|
||||
}
|
||||
|
||||
inline void check_error_code(const error_code& errc)
|
||||
inline void check_error_code(const error_code& errc, const error_info& info)
|
||||
{
|
||||
if (errc)
|
||||
{
|
||||
throw boost::system::system_error(errc);
|
||||
throw boost::system::system_error(errc, info.message());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,4 +78,4 @@ inline void check_error_code(const error_code& errc)
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -26,11 +26,12 @@ void hanshake(
|
||||
ChannelType& channel,
|
||||
const handshake_params& params,
|
||||
bytestring& buffer,
|
||||
error_code& err
|
||||
error_code& err,
|
||||
error_info& info
|
||||
);
|
||||
|
||||
template <typename ChannelType, typename CompletionToken>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void(error_code))
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void(error_code, error_info))
|
||||
async_handshake(
|
||||
ChannelType& channel,
|
||||
const handshake_params& params,
|
||||
@@ -44,4 +45,4 @@ async_handshake(
|
||||
#include "mysql/impl/handshake.ipp"
|
||||
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -21,7 +21,8 @@ inline std::uint8_t get_collation_first_byte(collation value)
|
||||
|
||||
inline error_code deserialize_handshake(
|
||||
boost::asio::const_buffer buffer,
|
||||
handshake_packet& output
|
||||
handshake_packet& output,
|
||||
error_info& info
|
||||
)
|
||||
{
|
||||
DeserializationContext ctx (boost::asio::buffer(buffer), capabilities());
|
||||
@@ -33,7 +34,7 @@ inline error_code deserialize_handshake(
|
||||
}
|
||||
else if (msg_type == error_packet_header)
|
||||
{
|
||||
return process_error_packet(ctx);
|
||||
return process_error_packet(ctx, info);
|
||||
}
|
||||
else if (msg_type != handshake_protocol_version_10)
|
||||
{
|
||||
@@ -127,11 +128,11 @@ public:
|
||||
);
|
||||
}
|
||||
|
||||
error_code process_handshake(bytestring& buffer)
|
||||
error_code process_handshake(bytestring& buffer, error_info& info)
|
||||
{
|
||||
// Deserialize server greeting
|
||||
handshake_packet handshake;
|
||||
auto err = deserialize_handshake(boost::asio::buffer(buffer), handshake);
|
||||
auto err = deserialize_handshake(boost::asio::buffer(buffer), handshake, info);
|
||||
if (err) return err;
|
||||
|
||||
// Check capabilities
|
||||
@@ -159,7 +160,8 @@ public:
|
||||
|
||||
error_code process_handshake_server_response(
|
||||
bytestring& buffer,
|
||||
bool& auth_complete
|
||||
bool& auth_complete,
|
||||
error_info& info
|
||||
)
|
||||
{
|
||||
DeserializationContext ctx (boost::asio::buffer(buffer), negotiated_caps_);
|
||||
@@ -174,7 +176,7 @@ public:
|
||||
}
|
||||
else if (msg_type == error_packet_header)
|
||||
{
|
||||
return process_error_packet(ctx);
|
||||
return process_error_packet(ctx, info);
|
||||
}
|
||||
else if (msg_type != auth_switch_request_header)
|
||||
{
|
||||
@@ -200,7 +202,8 @@ public:
|
||||
}
|
||||
|
||||
error_code process_auth_switch_response(
|
||||
boost::asio::const_buffer buffer
|
||||
boost::asio::const_buffer buffer,
|
||||
error_info& info
|
||||
)
|
||||
{
|
||||
DeserializationContext ctx (boost::asio::buffer(buffer), negotiated_caps_);
|
||||
@@ -208,7 +211,7 @@ public:
|
||||
if (err) return err;
|
||||
if (msg_type == error_packet_header)
|
||||
{
|
||||
return process_error_packet(ctx);
|
||||
return process_error_packet(ctx, info);
|
||||
}
|
||||
else if (msg_type != ok_packet_header)
|
||||
{
|
||||
@@ -228,9 +231,12 @@ void mysql::detail::hanshake(
|
||||
ChannelType& channel,
|
||||
const handshake_params& params,
|
||||
bytestring& buffer,
|
||||
error_code& err
|
||||
error_code& err,
|
||||
error_info& info
|
||||
)
|
||||
{
|
||||
info.clear();
|
||||
|
||||
// Set up processor
|
||||
handshake_processor processor (params);
|
||||
|
||||
@@ -239,7 +245,7 @@ void mysql::detail::hanshake(
|
||||
if (err) return;
|
||||
|
||||
// Process server greeting
|
||||
err = processor.process_handshake(buffer);
|
||||
err = processor.process_handshake(buffer, info);
|
||||
if (err) return;
|
||||
|
||||
// Send
|
||||
@@ -252,7 +258,7 @@ void mysql::detail::hanshake(
|
||||
|
||||
// Process it
|
||||
bool auth_complete = false;
|
||||
err = processor.process_handshake_server_response(buffer, auth_complete);
|
||||
err = processor.process_handshake_server_response(buffer, auth_complete, info);
|
||||
if (err) return;
|
||||
if (auth_complete)
|
||||
{
|
||||
@@ -269,14 +275,14 @@ void mysql::detail::hanshake(
|
||||
if (err) return;
|
||||
|
||||
// Process it
|
||||
err = processor.process_auth_switch_response(boost::asio::buffer(buffer));
|
||||
err = processor.process_auth_switch_response(boost::asio::buffer(buffer), info);
|
||||
if (err) return;
|
||||
|
||||
channel.set_current_capabilities(processor.negotiated_capabilities());
|
||||
}
|
||||
|
||||
template <typename ChannelType, typename CompletionToken>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void(mysql::error_code))
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void(mysql::error_code, mysql::error_info))
|
||||
mysql::detail::async_handshake(
|
||||
ChannelType& channel,
|
||||
const handshake_params& params,
|
||||
@@ -284,7 +290,7 @@ mysql::detail::async_handshake(
|
||||
CompletionToken&& token
|
||||
)
|
||||
{
|
||||
using HandlerSignature = void(mysql::error_code);
|
||||
using HandlerSignature = void(error_code, error_info);
|
||||
using HandlerType = BOOST_ASIO_HANDLER_TYPE(CompletionToken, HandlerSignature);
|
||||
using StreamType = typename ChannelType::stream_type;
|
||||
using BaseType = boost::beast::async_base<HandlerType, typename StreamType::executor_type>;
|
||||
@@ -296,6 +302,7 @@ mysql::detail::async_handshake(
|
||||
ChannelType& channel_;
|
||||
bytestring& buffer_;
|
||||
handshake_processor processor_;
|
||||
error_info info_;
|
||||
|
||||
Op(
|
||||
HandlerType&& handler,
|
||||
@@ -313,7 +320,7 @@ mysql::detail::async_handshake(
|
||||
void complete(bool cont, error_code errc)
|
||||
{
|
||||
channel_.set_current_capabilities(processor_.negotiated_capabilities());
|
||||
BaseType::complete(cont, errc);
|
||||
BaseType::complete(cont, errc, std::move(info_));
|
||||
}
|
||||
|
||||
void operator()(
|
||||
@@ -333,7 +340,7 @@ mysql::detail::async_handshake(
|
||||
}
|
||||
|
||||
// Process server greeting
|
||||
err = processor_.process_handshake(buffer_);
|
||||
err = processor_.process_handshake(buffer_, info_);
|
||||
if (err)
|
||||
{
|
||||
complete(cont, err);
|
||||
@@ -357,7 +364,7 @@ mysql::detail::async_handshake(
|
||||
}
|
||||
|
||||
// Process it
|
||||
err = processor_.process_handshake_server_response(buffer_, auth_complete);
|
||||
err = processor_.process_handshake_server_response(buffer_, auth_complete, info_);
|
||||
if (auth_complete) err.clear();
|
||||
if (err || auth_complete)
|
||||
{
|
||||
@@ -382,7 +389,7 @@ mysql::detail::async_handshake(
|
||||
}
|
||||
|
||||
// Process it
|
||||
err = processor_.process_auth_switch_response(boost::asio::buffer(buffer_));
|
||||
err = processor_.process_auth_switch_response(boost::asio::buffer(buffer_), info_);
|
||||
if (err)
|
||||
{
|
||||
complete(cont, err);
|
||||
|
||||
@@ -232,7 +232,7 @@ inline std::pair<error_code, std::uint8_t> deserialize_message_type(
|
||||
DeserializationContext& ctx
|
||||
);
|
||||
|
||||
inline error_code process_error_packet(DeserializationContext& ctx);
|
||||
inline error_code process_error_packet(DeserializationContext& ctx, error_info& info);
|
||||
|
||||
|
||||
/*struct StmtPrepare
|
||||
|
||||
@@ -214,12 +214,14 @@ inline std::pair<mysql::error_code, std::uint8_t> mysql::detail::deserialize_mes
|
||||
}
|
||||
|
||||
inline mysql::error_code mysql::detail::process_error_packet(
|
||||
DeserializationContext& ctx
|
||||
DeserializationContext& ctx,
|
||||
error_info& info
|
||||
)
|
||||
{
|
||||
err_packet error_packet;
|
||||
auto errc = deserialize_message(error_packet, ctx);
|
||||
if (errc) return errc;
|
||||
info.set_message(std::string(error_packet.error_message.value));
|
||||
return make_error_code(static_cast<Error>(error_packet.error_code.value));
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define MYSQL_ASIO_IMPL_QUERY_HPP
|
||||
|
||||
#include "mysql/resultset.hpp"
|
||||
#include "mysql/error.hpp"
|
||||
#include "mysql/impl/capabilities.hpp"
|
||||
#include <string_view>
|
||||
|
||||
@@ -28,11 +29,12 @@ void execute_query(
|
||||
ChannelType& channel,
|
||||
std::string_view query,
|
||||
channel_resultset_type<ChannelType>& output,
|
||||
error_code& err
|
||||
error_code& err,
|
||||
error_info& info
|
||||
);
|
||||
|
||||
template <typename ChannelType, typename CompletionToken>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void(error_code, channel_resultset_type<ChannelType>))
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void(error_code, error_info, channel_resultset_type<ChannelType>))
|
||||
async_execute_query(
|
||||
ChannelType& channel,
|
||||
std::string_view query,
|
||||
@@ -47,11 +49,12 @@ fetch_result fetch_text_row(
|
||||
bytestring& buffer,
|
||||
std::vector<value>& output_values,
|
||||
ok_packet& output_ok_packet,
|
||||
error_code& err
|
||||
error_code& err,
|
||||
error_info& info
|
||||
);
|
||||
|
||||
template <typename ChannelType, typename CompletionToken>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void(error_code, fetch_result))
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void(error_code, error_info, fetch_result))
|
||||
async_fetch_text_row(
|
||||
ChannelType& channel,
|
||||
const std::vector<field_metadata>& meta,
|
||||
|
||||
@@ -41,7 +41,8 @@ public:
|
||||
std::optional<std::uint64_t> // has value if there are fields in the response
|
||||
process_query_response(
|
||||
channel_resultset_type<ChannelType>& output,
|
||||
error_code& err
|
||||
error_code& err,
|
||||
error_info& info
|
||||
)
|
||||
{
|
||||
// Response may be: ok_packet, err_packet, local infile request (not implemented)
|
||||
@@ -62,7 +63,7 @@ public:
|
||||
}
|
||||
else if (msg_type == error_packet_header)
|
||||
{
|
||||
err = process_error_packet(ctx);
|
||||
err = process_error_packet(ctx, info);
|
||||
return {};
|
||||
}
|
||||
else
|
||||
@@ -117,7 +118,8 @@ inline fetch_result process_fetch_message(
|
||||
const bytestring& buffer,
|
||||
std::vector<value>& output_values,
|
||||
ok_packet& output_ok_packet,
|
||||
error_code& err
|
||||
error_code& err,
|
||||
error_info& info
|
||||
)
|
||||
{
|
||||
// Message type: row, error or eof?
|
||||
@@ -135,7 +137,7 @@ inline fetch_result process_fetch_message(
|
||||
else if (msg_type == error_packet_header)
|
||||
{
|
||||
// An error occurred during the generation of the rows
|
||||
err = process_error_packet(ctx);
|
||||
err = process_error_packet(ctx, info);
|
||||
return fetch_result::error;
|
||||
}
|
||||
else
|
||||
@@ -156,7 +158,8 @@ void mysql::detail::execute_query(
|
||||
ChannelType& channel,
|
||||
std::string_view query,
|
||||
resultset<channel_stream_type<ChannelType>>& output,
|
||||
error_code& err
|
||||
error_code& err,
|
||||
error_info& info
|
||||
)
|
||||
{
|
||||
// Compose a com_query message, reset seq num
|
||||
@@ -172,7 +175,7 @@ void mysql::detail::execute_query(
|
||||
if (err) return;
|
||||
|
||||
// Response may be: ok_packet, err_packet, local infile request (not implemented), or response with fields
|
||||
auto num_fields = processor.process_query_response(output, err);
|
||||
auto num_fields = processor.process_query_response(output, err, info);
|
||||
if (!num_fields) // ok or err
|
||||
{
|
||||
return;
|
||||
@@ -199,7 +202,7 @@ void mysql::detail::execute_query(
|
||||
template <typename ChannelType, typename CompletionToken>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(
|
||||
CompletionToken,
|
||||
void(mysql::error_code, mysql::detail::channel_resultset_type<ChannelType>)
|
||||
void(mysql::error_code, mysql::error_info, mysql::detail::channel_resultset_type<ChannelType>)
|
||||
)
|
||||
mysql::detail::async_execute_query(
|
||||
ChannelType& channel,
|
||||
@@ -207,7 +210,7 @@ mysql::detail::async_execute_query(
|
||||
CompletionToken&& token
|
||||
)
|
||||
{
|
||||
using HandlerSignature = void(error_code, channel_resultset_type<ChannelType>);
|
||||
using HandlerSignature = void(error_code, error_info, channel_resultset_type<ChannelType>);
|
||||
using HandlerType = BOOST_ASIO_HANDLER_TYPE(CompletionToken, HandlerSignature);
|
||||
using StreamType = typename ChannelType::stream_type;
|
||||
using BaseType = boost::beast::async_base<HandlerType, typename StreamType::executor_type>;
|
||||
@@ -236,10 +239,11 @@ mysql::detail::async_execute_query(
|
||||
{
|
||||
ResultsetType resultset;
|
||||
error_code err;
|
||||
auto num_fields = processor_->process_query_response(resultset, err);
|
||||
error_info info;
|
||||
auto num_fields = processor_->process_query_response(resultset, err, info);
|
||||
if (!num_fields) // ok or err
|
||||
{
|
||||
this->complete(cont, err, std::move(resultset));
|
||||
this->complete(cont, err, std::move(info), std::move(resultset));
|
||||
return false;
|
||||
}
|
||||
else
|
||||
@@ -253,7 +257,7 @@ mysql::detail::async_execute_query(
|
||||
{
|
||||
ResultsetType resultset;
|
||||
std::move(*processor_).create_resultset(resultset);
|
||||
this->complete(cont, error_code(), std::move(resultset));
|
||||
this->complete(cont, error_code(), error_info(), std::move(resultset));
|
||||
}
|
||||
|
||||
void operator()(
|
||||
@@ -270,7 +274,7 @@ mysql::detail::async_execute_query(
|
||||
);
|
||||
if (err)
|
||||
{
|
||||
this->complete(cont, err, ResultsetType());
|
||||
this->complete(cont, err, error_info(), ResultsetType());
|
||||
yield break;
|
||||
}
|
||||
|
||||
@@ -281,7 +285,7 @@ mysql::detail::async_execute_query(
|
||||
);
|
||||
if (err)
|
||||
{
|
||||
this->complete(cont, err, ResultsetType());
|
||||
this->complete(cont, err, error_info(), ResultsetType());
|
||||
yield break;
|
||||
}
|
||||
|
||||
@@ -308,7 +312,7 @@ mysql::detail::async_execute_query(
|
||||
|
||||
if (err)
|
||||
{
|
||||
this->complete(cont, err, ResultsetType());
|
||||
this->complete(cont, err, error_info(), ResultsetType());
|
||||
yield break;
|
||||
}
|
||||
|
||||
@@ -339,7 +343,8 @@ mysql::detail::fetch_result mysql::detail::fetch_text_row(
|
||||
bytestring& buffer,
|
||||
std::vector<value>& output_values,
|
||||
ok_packet& output_ok_packet,
|
||||
error_code& err
|
||||
error_code& err,
|
||||
error_info& info
|
||||
)
|
||||
{
|
||||
// Read a packet
|
||||
@@ -352,13 +357,17 @@ mysql::detail::fetch_result mysql::detail::fetch_text_row(
|
||||
buffer,
|
||||
output_values,
|
||||
output_ok_packet,
|
||||
err
|
||||
err,
|
||||
info
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
template <typename ChannelType, typename CompletionToken>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void(mysql::error_code, mysql::detail::fetch_result))
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(
|
||||
CompletionToken,
|
||||
void(mysql::error_code, mysql::error_info, mysql::detail::fetch_result)
|
||||
)
|
||||
mysql::detail::async_fetch_text_row(
|
||||
ChannelType& channel,
|
||||
const std::vector<field_metadata>& meta,
|
||||
@@ -401,15 +410,17 @@ mysql::detail::async_fetch_text_row(
|
||||
void process_result(bool cont)
|
||||
{
|
||||
error_code err;
|
||||
error_info info;
|
||||
auto result = process_fetch_message(
|
||||
channel_.current_capabilities(),
|
||||
meta_,
|
||||
buffer_,
|
||||
output_values_,
|
||||
output_ok_packet_,
|
||||
err
|
||||
err,
|
||||
info
|
||||
);
|
||||
this->complete(cont, err, result);
|
||||
this->complete(cont, err, info, result);
|
||||
}
|
||||
|
||||
void operator()(
|
||||
@@ -422,7 +433,7 @@ mysql::detail::async_fetch_text_row(
|
||||
yield channel_.async_read(buffer_, std::move(*this));
|
||||
if (err)
|
||||
{
|
||||
this->complete(cont, err, fetch_result::error);
|
||||
this->complete(cont, err, error_info(), fetch_result::error);
|
||||
yield break;
|
||||
}
|
||||
process_result(cont);
|
||||
|
||||
@@ -9,13 +9,17 @@
|
||||
|
||||
template <typename StreamType>
|
||||
const mysql::row* mysql::resultset<StreamType>::fetch_one(
|
||||
error_code& err
|
||||
error_code& err,
|
||||
error_info& info
|
||||
)
|
||||
{
|
||||
assert(valid());
|
||||
|
||||
err.clear();
|
||||
info.clear();
|
||||
|
||||
if (complete())
|
||||
{
|
||||
err.clear();
|
||||
return nullptr;
|
||||
}
|
||||
auto result = detail::fetch_text_row(
|
||||
@@ -24,7 +28,8 @@ const mysql::row* mysql::resultset<StreamType>::fetch_one(
|
||||
buffer_,
|
||||
current_row_.values(),
|
||||
ok_packet_,
|
||||
err
|
||||
err,
|
||||
info
|
||||
);
|
||||
eof_received_ = result == detail::fetch_result::eof;
|
||||
return result == detail::fetch_result::row ? ¤t_row_ : nullptr;
|
||||
@@ -34,20 +39,24 @@ template <typename StreamType>
|
||||
const mysql::row* mysql::resultset<StreamType>::fetch_one()
|
||||
{
|
||||
error_code errc;
|
||||
const row* res = fetch_one(errc);
|
||||
detail::check_error_code(errc);
|
||||
error_info info;
|
||||
const row* res = fetch_one(errc, info);
|
||||
detail::check_error_code(errc, info);
|
||||
return res;
|
||||
}
|
||||
|
||||
template <typename StreamType>
|
||||
std::vector<mysql::owning_row> mysql::resultset<StreamType>::fetch_many(
|
||||
std::size_t count,
|
||||
error_code& err
|
||||
error_code& err,
|
||||
error_info& info
|
||||
)
|
||||
{
|
||||
assert(valid());
|
||||
|
||||
err.clear();
|
||||
info.clear();
|
||||
|
||||
std::vector<mysql::owning_row> res;
|
||||
|
||||
if (!complete()) // support calling fetch on already exhausted resultset
|
||||
@@ -63,7 +72,8 @@ std::vector<mysql::owning_row> mysql::resultset<StreamType>::fetch_many(
|
||||
buff,
|
||||
values,
|
||||
ok_packet_,
|
||||
err
|
||||
err,
|
||||
info
|
||||
);
|
||||
eof_received_ = result == detail::fetch_result::eof;
|
||||
if (result == detail::fetch_result::row)
|
||||
@@ -86,17 +96,19 @@ std::vector<mysql::owning_row> mysql::resultset<StreamType>::fetch_many(
|
||||
)
|
||||
{
|
||||
error_code errc;
|
||||
auto res = fetch_many(count, errc);
|
||||
detail::check_error_code(errc);
|
||||
error_info info;
|
||||
auto res = fetch_many(count, errc, info);
|
||||
detail::check_error_code(errc, info);
|
||||
return res;
|
||||
}
|
||||
|
||||
template <typename StreamType>
|
||||
std::vector<mysql::owning_row> mysql::resultset<StreamType>::fetch_all(
|
||||
error_code& err
|
||||
error_code& err,
|
||||
error_info& info
|
||||
)
|
||||
{
|
||||
return fetch_many(std::numeric_limits<std::size_t>::max(), err);
|
||||
return fetch_many(std::numeric_limits<std::size_t>::max(), err, info);
|
||||
}
|
||||
|
||||
template <typename StreamType>
|
||||
@@ -107,12 +119,15 @@ std::vector<mysql::owning_row> mysql::resultset<StreamType>::fetch_all()
|
||||
|
||||
template <typename StreamType>
|
||||
template <typename CompletionToken>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void(mysql::error_code, const mysql::row*))
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(
|
||||
CompletionToken,
|
||||
void(mysql::error_code, mysql::error_info, const mysql::row*)
|
||||
)
|
||||
mysql::resultset<StreamType>::async_fetch_one(
|
||||
CompletionToken&& token
|
||||
)
|
||||
{
|
||||
using HandlerSignature = void(error_code, const row*);
|
||||
using HandlerSignature = void(error_code, error_info, const row*);
|
||||
using HandlerType = BOOST_ASIO_HANDLER_TYPE(CompletionToken, HandlerSignature);
|
||||
using BaseType = boost::beast::async_base<HandlerType, typename StreamType::executor_type>;
|
||||
|
||||
@@ -129,6 +144,7 @@ mysql::resultset<StreamType>::async_fetch_one(
|
||||
|
||||
void operator()(
|
||||
error_code err,
|
||||
error_info info,
|
||||
detail::fetch_result result,
|
||||
bool cont=true
|
||||
)
|
||||
@@ -137,7 +153,7 @@ mysql::resultset<StreamType>::async_fetch_one(
|
||||
{
|
||||
if (resultset_.complete())
|
||||
{
|
||||
this->complete(cont, error_code(), nullptr);
|
||||
this->complete(cont, error_code(), error_info(), nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -153,6 +169,7 @@ mysql::resultset<StreamType>::async_fetch_one(
|
||||
this->complete(
|
||||
cont,
|
||||
err,
|
||||
std::move(info),
|
||||
result == detail::fetch_result::row ? &resultset_.current_row_ : nullptr
|
||||
);
|
||||
}
|
||||
@@ -167,19 +184,22 @@ mysql::resultset<StreamType>::async_fetch_one(
|
||||
Op(
|
||||
std::move(initiator.completion_handler),
|
||||
*this
|
||||
)(error_code(), detail::fetch_result::error, false);
|
||||
)(error_code(), error_info(), detail::fetch_result::error, false);
|
||||
return initiator.result.get();
|
||||
}
|
||||
|
||||
template <typename StreamType>
|
||||
template <typename CompletionToken>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void(mysql::error_code, std::vector<mysql::owning_row>))
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(
|
||||
CompletionToken,
|
||||
void(mysql::error_code, mysql::error_info, std::vector<mysql::owning_row>)
|
||||
)
|
||||
mysql::resultset<StreamType>::async_fetch_many(
|
||||
std::size_t count,
|
||||
CompletionToken&& token
|
||||
)
|
||||
{
|
||||
using HandlerSignature = void(error_code, std::vector<owning_row>);
|
||||
using HandlerSignature = void(error_code, error_info, std::vector<owning_row>);
|
||||
using HandlerType = BOOST_ASIO_HANDLER_TYPE(CompletionToken, HandlerSignature);
|
||||
using BaseType = boost::beast::async_base<HandlerType, typename StreamType::executor_type>;
|
||||
|
||||
@@ -218,6 +238,7 @@ mysql::resultset<StreamType>::async_fetch_many(
|
||||
|
||||
void operator()(
|
||||
error_code err,
|
||||
error_info info,
|
||||
detail::fetch_result result,
|
||||
bool cont=true
|
||||
)
|
||||
@@ -236,7 +257,7 @@ mysql::resultset<StreamType>::async_fetch_many(
|
||||
);
|
||||
if (result == detail::fetch_result::error)
|
||||
{
|
||||
this->complete(cont, err, std::move(impl_->rows));
|
||||
this->complete(cont, err, std::move(info), std::move(impl_->rows));
|
||||
yield break;
|
||||
}
|
||||
else if (result == detail::fetch_result::eof)
|
||||
@@ -248,7 +269,7 @@ mysql::resultset<StreamType>::async_fetch_many(
|
||||
impl_->row_received();
|
||||
}
|
||||
}
|
||||
this->complete(cont, err, std::move(impl_->rows));
|
||||
this->complete(cont, err, error_info(), std::move(impl_->rows));
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -260,13 +281,16 @@ mysql::resultset<StreamType>::async_fetch_many(
|
||||
Op(
|
||||
std::move(initiator.completion_handler),
|
||||
std::make_shared<OpImpl>(*this, count)
|
||||
)(error_code(), detail::fetch_result::error, false);
|
||||
)(error_code(), error_info(), detail::fetch_result::error, false);
|
||||
return initiator.result.get();
|
||||
}
|
||||
|
||||
template <typename StreamType>
|
||||
template <typename CompletionToken>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void(mysql::error_code, std::vector<mysql::owning_row>))
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(
|
||||
CompletionToken,
|
||||
void(mysql::error_code, mysql::error_info, std::vector<mysql::owning_row>)
|
||||
)
|
||||
mysql::resultset<StreamType>::async_fetch_all(
|
||||
CompletionToken&& token
|
||||
)
|
||||
@@ -281,4 +305,4 @@ mysql::resultset<StreamType>::async_fetch_all(
|
||||
#include <boost/asio/unyield.hpp>
|
||||
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -77,7 +77,7 @@ public:
|
||||
* fetch_one is the fetch method that performs the less memory allocations
|
||||
* of the three.
|
||||
*/
|
||||
const row* fetch_one(error_code& err);
|
||||
const row* fetch_one(error_code& err, error_info& info);
|
||||
|
||||
/// Fetches a single row (sync with exceptions version).
|
||||
const row* fetch_one();
|
||||
@@ -91,7 +91,7 @@ public:
|
||||
* 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);
|
||||
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);
|
||||
@@ -104,24 +104,24 @@ public:
|
||||
*
|
||||
* The resultset is guaranteed to be complete() after this call returns.
|
||||
*/
|
||||
std::vector<owning_row> fetch_all(error_code& err);
|
||||
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, const row*))
|
||||
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, std::vector<owning_row>))
|
||||
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, std::vector<owning_row>))
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void(error_code, error_info, std::vector<owning_row>))
|
||||
async_fetch_all(CompletionToken&& token);
|
||||
|
||||
/**
|
||||
@@ -177,6 +177,6 @@ using tcp_resultset = resultset<boost::asio::ip::tcp::socket>;
|
||||
|
||||
}
|
||||
|
||||
#include "mysql/impl/resultset.hpp"
|
||||
#include "mysql/impl/resultset.ipp"
|
||||
|
||||
#endif
|
||||
|
||||
@@ -25,9 +25,9 @@ add_executable(
|
||||
unit/row.cpp
|
||||
)
|
||||
# A codegen issue in MSVC C++17 makes gmock expectations not work
|
||||
if (NOT MSVC)
|
||||
target_sources(mysql_unittests PRIVATE unit/channel.cpp)
|
||||
endif()
|
||||
#if (NOT MSVC)
|
||||
# target_sources(mysql_unittests PRIVATE unit/channel.cpp)
|
||||
#endif()
|
||||
|
||||
target_include_directories(
|
||||
mysql_unittests
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "mysql/value.hpp"
|
||||
#include "mysql/row.hpp"
|
||||
#include <gmock/gmock.h>
|
||||
#include <vector>
|
||||
|
||||
namespace mysql
|
||||
@@ -62,6 +63,16 @@ inline std::string_view makesv(const std::uint8_t (&value) [N])
|
||||
return std::string_view(reinterpret_cast<const char*>(value), N);
|
||||
}
|
||||
|
||||
inline void validate_error_info(const mysql::error_info& value, const std::vector<std::string>& to_check)
|
||||
{
|
||||
std::string msg_lower = value.message();
|
||||
std::transform(msg_lower.begin(), msg_lower.end(), msg_lower.begin(), &tolower);
|
||||
for (const auto& elm: to_check)
|
||||
{
|
||||
EXPECT_THAT(msg_lower, testing::HasSubstr(elm));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,12 +7,15 @@
|
||||
|
||||
#include "mysql/connection.hpp"
|
||||
#include "integration_test_common.hpp"
|
||||
#include "test_common.hpp"
|
||||
#include <boost/asio/use_future.hpp>
|
||||
|
||||
namespace net = boost::asio;
|
||||
using namespace testing;
|
||||
using namespace mysql::test;
|
||||
|
||||
using mysql::detail::make_error_code;
|
||||
using mysql::error_info;
|
||||
|
||||
namespace
|
||||
{
|
||||
@@ -24,8 +27,9 @@ struct HandshakeTest : public mysql::test::IntegTest
|
||||
// Sync with error codes
|
||||
TEST_F(HandshakeTest, SyncErrc_FastAuthSuccessfulLogin)
|
||||
{
|
||||
conn.handshake(connection_params, errc);
|
||||
conn.handshake(connection_params, errc, info);
|
||||
EXPECT_EQ(errc, mysql::error_code());
|
||||
EXPECT_EQ(info, error_info());
|
||||
}
|
||||
|
||||
// TODO: review failure in Mac
|
||||
@@ -40,15 +44,17 @@ TEST_F(HandshakeTest, SyncErrc_FastAuthSuccessfulLogin)
|
||||
TEST_F(HandshakeTest, SyncErrc_FastAuthSuccessfulLoginNoDatabase)
|
||||
{
|
||||
connection_params.database = "";
|
||||
conn.handshake(connection_params, errc);
|
||||
conn.handshake(connection_params, errc, info);
|
||||
EXPECT_EQ(errc, mysql::error_code());
|
||||
EXPECT_EQ(info, error_info());
|
||||
}
|
||||
|
||||
TEST_F(HandshakeTest, SyncErrc_FastAuthBadUser)
|
||||
{
|
||||
connection_params.username = "non_existing_user";
|
||||
conn.handshake(connection_params, errc);
|
||||
conn.handshake(connection_params, errc, info);
|
||||
EXPECT_NE(errc, mysql::error_code());
|
||||
EXPECT_NE(info, error_info());
|
||||
// TODO: if default auth plugin is unknown, unknown auth plugin is returned instead of access denied
|
||||
// EXPECT_EQ(errc, make_error_code(mysql::Error::access_denied_error));
|
||||
}
|
||||
@@ -56,15 +62,17 @@ TEST_F(HandshakeTest, SyncErrc_FastAuthBadUser)
|
||||
TEST_F(HandshakeTest, SyncErrc_FastAuthBadPassword)
|
||||
{
|
||||
connection_params.password = "bad_password";
|
||||
conn.handshake(connection_params, errc);
|
||||
conn.handshake(connection_params, errc, info);
|
||||
EXPECT_EQ(errc, make_error_code(mysql::Error::access_denied_error));
|
||||
validate_error_info(info, {"access denied", "integ_user"});
|
||||
}
|
||||
|
||||
TEST_F(HandshakeTest, SyncErrc_FastAuthBadDatabase)
|
||||
{
|
||||
connection_params.database = "bad_database";
|
||||
conn.handshake(connection_params, errc);
|
||||
conn.handshake(connection_params, errc, info);
|
||||
EXPECT_EQ(errc, make_error_code(mysql::Error::bad_db_error));
|
||||
validate_error_info(info, {"unknown database", "bad_database"});
|
||||
}
|
||||
|
||||
// Sync with exceptions
|
||||
@@ -83,7 +91,7 @@ TEST_F(HandshakeTest, SyncExc_FastAuthBadPassword)
|
||||
TEST_F(HandshakeTest, Async_FastAuthSuccessfulLogin)
|
||||
{
|
||||
auto fut = conn.async_handshake(connection_params, boost::asio::use_future);
|
||||
EXPECT_NO_THROW(fut.get());
|
||||
EXPECT_EQ(fut.get(), error_info());
|
||||
}
|
||||
|
||||
// TODO: review failure in Mac
|
||||
@@ -92,21 +100,20 @@ TEST_F(HandshakeTest, Async_FastAuthSuccessfulLogin)
|
||||
connection_params.username = "empty_password_user";
|
||||
connection_params.password = "";
|
||||
auto fut = conn.async_handshake(connection_params, boost::asio::use_future);
|
||||
EXPECT_NO_THROW(fut.get());
|
||||
EXPECT_EQ(fut.get(), error_info());
|
||||
}*/
|
||||
|
||||
TEST_F(HandshakeTest, Async_FastAuthSuccessfulLoginNoDatabase)
|
||||
{
|
||||
connection_params.database = "";
|
||||
auto fut = conn.async_handshake(connection_params, boost::asio::use_future);
|
||||
EXPECT_NO_THROW(fut.get());
|
||||
EXPECT_EQ(fut.get(), error_info());
|
||||
}
|
||||
|
||||
TEST_F(HandshakeTest, Async_FastAuthBadUser)
|
||||
{
|
||||
connection_params.username = "non_existing_user";
|
||||
auto fut = conn.async_handshake(connection_params, boost::asio::use_future);
|
||||
|
||||
EXPECT_THROW(fut.get(), boost::system::system_error);
|
||||
// TODO: if default auth plugin is unknown, unknown auth plugin is returned instead of access denied
|
||||
// validate_future_exception(fut, make_error_code(mysql::Error::access_denied_error));
|
||||
@@ -115,15 +122,17 @@ TEST_F(HandshakeTest, Async_FastAuthBadUser)
|
||||
TEST_F(HandshakeTest, Async_FastAuthBadPassword)
|
||||
{
|
||||
connection_params.password = "bad_password";
|
||||
auto fut = conn.async_handshake(connection_params, boost::asio::use_future);
|
||||
validate_future_exception(fut, make_error_code(mysql::Error::access_denied_error));
|
||||
validate_async_fail([&](auto&& cb) {
|
||||
conn.async_handshake(connection_params, std::move(cb));
|
||||
}, mysql::Error::access_denied_error, {"access denied", "integ_user"});
|
||||
}
|
||||
|
||||
TEST_F(HandshakeTest, Async_FastAuthBadDatabase)
|
||||
{
|
||||
connection_params.database = "bad_db";
|
||||
auto fut = conn.async_handshake(connection_params, boost::asio::use_future);
|
||||
validate_future_exception(fut, make_error_code(mysql::Error::bad_db_error));
|
||||
validate_async_fail([&](auto&& cb) {
|
||||
conn.async_handshake(connection_params, std::move(cb));
|
||||
}, mysql::Error::bad_db_error, {"unknown database", "bad_db"});
|
||||
}
|
||||
|
||||
} // anon namespace
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <future>
|
||||
#include <thread>
|
||||
#include "test_common.hpp"
|
||||
|
||||
namespace mysql
|
||||
{
|
||||
@@ -19,6 +20,7 @@ struct IntegTest : testing::Test
|
||||
boost::asio::io_context ctx;
|
||||
mysql::connection<boost::asio::ip::tcp::socket> conn {ctx};
|
||||
mysql::error_code errc;
|
||||
mysql::error_info info;
|
||||
boost::asio::executor_work_guard<boost::asio::io_context::executor_type> guard { ctx.get_executor() };
|
||||
std::thread runner {[this]{ ctx.run(); } };
|
||||
|
||||
@@ -26,6 +28,7 @@ struct IntegTest : testing::Test
|
||||
{
|
||||
boost::asio::ip::tcp::endpoint endpoint (boost::asio::ip::address_v4::loopback(), 3306);
|
||||
conn.next_level().connect(endpoint);
|
||||
reset_errors();
|
||||
}
|
||||
|
||||
~IntegTest()
|
||||
@@ -35,24 +38,46 @@ struct IntegTest : testing::Test
|
||||
runner.join();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void validate_future_exception(std::future<T>& fut, mysql::error_code expected_errc)
|
||||
template <typename Callable>
|
||||
void validate_async_fail(
|
||||
Callable&& initiator,
|
||||
error_code expected_errc,
|
||||
const std::vector<std::string>& expected_info
|
||||
)
|
||||
{
|
||||
try
|
||||
{
|
||||
fut.get();
|
||||
FAIL() << "Expected asynchronous operation to fail";
|
||||
}
|
||||
catch (const boost::system::system_error& exc)
|
||||
{
|
||||
EXPECT_EQ(exc.code(), expected_errc);
|
||||
}
|
||||
std::promise<std::pair<error_code, error_info>> prom;
|
||||
initiator([&prom](error_code errc, error_info info, auto&&...) {
|
||||
prom.set_value(std::make_pair(errc, std::move(info)));
|
||||
});
|
||||
auto [actual_errc, actual_info] = prom.get_future().get();
|
||||
EXPECT_EQ(actual_errc, expected_errc);
|
||||
validate_error_info(actual_info, expected_info);
|
||||
}
|
||||
|
||||
template <typename Callable>
|
||||
void validate_async_fail(
|
||||
Callable&& initiator,
|
||||
Error expected_errc,
|
||||
const std::vector<std::string>& expected_info
|
||||
)
|
||||
{
|
||||
validate_async_fail(
|
||||
std::forward<Callable>(initiator),
|
||||
::mysql::detail::make_error_code(expected_errc),
|
||||
expected_info
|
||||
);
|
||||
}
|
||||
|
||||
void handshake()
|
||||
{
|
||||
conn.handshake(connection_params);
|
||||
}
|
||||
|
||||
void reset_errors()
|
||||
{
|
||||
// TODO: set errc to something not null to verify we clear stuff
|
||||
info.set_message("Previous error message was not cleared correctly");
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ using mysql::test::validate_meta;
|
||||
using mysql::field_metadata;
|
||||
using mysql::field_type;
|
||||
using mysql::error_code;
|
||||
using mysql::error_info;
|
||||
|
||||
namespace
|
||||
{
|
||||
@@ -68,14 +69,22 @@ struct QueryTest : public mysql::test::IntegTest
|
||||
{
|
||||
validate_2fields_meta(result.fields(), table);
|
||||
}
|
||||
|
||||
auto make_query_initiator(const char* sql)
|
||||
{
|
||||
return [this, sql](auto&& cb) {
|
||||
conn.async_query(sql, cb);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
// Query, sync errc
|
||||
TEST_F(QueryTest, QuerySyncErrc_InsertQueryOk)
|
||||
{
|
||||
auto result = conn.query(
|
||||
"INSERT INTO inserts_table (field_varchar, field_date) VALUES ('v0', '2010-10-11')", errc);
|
||||
ASSERT_EQ(errc, mysql::error_code());
|
||||
const char* sql = "INSERT INTO inserts_table (field_varchar, field_date) VALUES ('v0', '2010-10-11')";
|
||||
auto result = conn.query(sql, errc, info);
|
||||
ASSERT_EQ(errc, error_code());
|
||||
EXPECT_EQ(info, error_info());
|
||||
EXPECT_TRUE(result.fields().empty());
|
||||
EXPECT_TRUE(result.valid());
|
||||
EXPECT_TRUE(result.complete());
|
||||
@@ -87,17 +96,19 @@ TEST_F(QueryTest, QuerySyncErrc_InsertQueryOk)
|
||||
|
||||
TEST_F(QueryTest, QuerySyncErrc_InsertQueryFailed)
|
||||
{
|
||||
auto result = conn.query(
|
||||
"INSERT INTO bad_table (field_varchar, field_date) VALUES ('v0', '2010-10-11')", errc);
|
||||
const char* sql = "INSERT INTO bad_table (field_varchar, field_date) VALUES ('v0', '2010-10-11')";
|
||||
auto result = conn.query(sql, errc, info);
|
||||
ASSERT_EQ(errc, make_error_code(mysql::Error::no_such_table));
|
||||
validate_error_info(info, {"table", "doesn't exist", "bad_table"});
|
||||
EXPECT_FALSE(result.valid());
|
||||
}
|
||||
|
||||
TEST_F(QueryTest, QuerySyncErrc_UpdateQueryOk)
|
||||
{
|
||||
auto result = conn.query(
|
||||
"UPDATE updates_table SET field_int = field_int+1", errc);
|
||||
const char* sql = "UPDATE updates_table SET field_int = field_int+1";
|
||||
auto result = conn.query(sql, errc, info);
|
||||
ASSERT_EQ(errc, mysql::error_code());
|
||||
EXPECT_EQ(info, error_info());
|
||||
EXPECT_TRUE(result.fields().empty());
|
||||
EXPECT_TRUE(result.valid());
|
||||
EXPECT_TRUE(result.complete());
|
||||
@@ -109,8 +120,9 @@ TEST_F(QueryTest, QuerySyncErrc_UpdateQueryOk)
|
||||
|
||||
TEST_F(QueryTest, QuerySyncErrc_SelectOk)
|
||||
{
|
||||
auto result = conn.query("SELECT * FROM empty_table", errc);
|
||||
auto result = conn.query("SELECT * FROM empty_table", errc, info);
|
||||
ASSERT_EQ(errc, mysql::error_code());
|
||||
EXPECT_EQ(info, error_info());
|
||||
EXPECT_TRUE(result.valid());
|
||||
EXPECT_FALSE(result.complete());
|
||||
validate_2fields_meta(result, "empty_table");
|
||||
@@ -118,8 +130,9 @@ TEST_F(QueryTest, QuerySyncErrc_SelectOk)
|
||||
|
||||
TEST_F(QueryTest, QuerySyncErrc_SelectQueryFailed)
|
||||
{
|
||||
auto result = conn.query("SELECT field_varchar, field_bad FROM one_row_table", errc);
|
||||
auto result = conn.query("SELECT field_varchar, field_bad FROM one_row_table", errc, info);
|
||||
ASSERT_EQ(errc, make_error_code(mysql::Error::bad_field_error));
|
||||
validate_error_info(info, {"unknown column", "field_bad"});
|
||||
EXPECT_FALSE(result.valid());
|
||||
}
|
||||
|
||||
@@ -148,10 +161,11 @@ TEST_F(QueryTest, QuerySyncExc_Error)
|
||||
// Query, async
|
||||
TEST_F(QueryTest, QueryAsync_InsertQueryOk)
|
||||
{
|
||||
auto result = conn.async_query(
|
||||
auto [info, result] = conn.async_query(
|
||||
"INSERT INTO inserts_table (field_varchar, field_date) VALUES ('v0', '2010-10-11')",
|
||||
net::use_future
|
||||
).get();
|
||||
EXPECT_EQ(info, error_info());
|
||||
EXPECT_TRUE(result.fields().empty());
|
||||
EXPECT_TRUE(result.valid());
|
||||
EXPECT_TRUE(result.complete());
|
||||
@@ -163,19 +177,20 @@ TEST_F(QueryTest, QueryAsync_InsertQueryOk)
|
||||
|
||||
TEST_F(QueryTest, QueryAsync_InsertQueryFailed)
|
||||
{
|
||||
auto fut = conn.async_query(
|
||||
"INSERT INTO bad_table (field_varchar, field_date) VALUES ('v0', '2010-10-11')",
|
||||
net::use_future
|
||||
validate_async_fail(
|
||||
make_query_initiator("INSERT INTO bad_table (field_varchar, field_date) VALUES ('v0', '2010-10-11')"),
|
||||
mysql::Error::no_such_table,
|
||||
{"table", "doesn't exist", "bad_table"}
|
||||
);
|
||||
validate_future_exception(fut, make_error_code(mysql::Error::no_such_table));
|
||||
}
|
||||
|
||||
TEST_F(QueryTest, QueryAsync_UpdateQueryOk)
|
||||
{
|
||||
auto result = conn.async_query(
|
||||
auto [info, result] = conn.async_query(
|
||||
"UPDATE updates_table SET field_int = field_int+1",
|
||||
net::use_future
|
||||
).get();
|
||||
EXPECT_EQ(info, error_info());
|
||||
EXPECT_TRUE(result.fields().empty());
|
||||
EXPECT_TRUE(result.valid());
|
||||
EXPECT_TRUE(result.complete());
|
||||
@@ -187,7 +202,8 @@ TEST_F(QueryTest, QueryAsync_UpdateQueryOk)
|
||||
|
||||
TEST_F(QueryTest, QueryAsync_SelectOk)
|
||||
{
|
||||
auto result = conn.async_query("SELECT * FROM empty_table", net::use_future).get();
|
||||
auto [info, result] = conn.async_query("SELECT * FROM empty_table", net::use_future).get();
|
||||
EXPECT_EQ(info, error_info());
|
||||
EXPECT_TRUE(result.valid());
|
||||
EXPECT_FALSE(result.complete());
|
||||
validate_2fields_meta(result, "empty_table");
|
||||
@@ -195,8 +211,11 @@ TEST_F(QueryTest, QueryAsync_SelectOk)
|
||||
|
||||
TEST_F(QueryTest, QueryAsync_SelectQueryFailed)
|
||||
{
|
||||
auto fut = conn.async_query("SELECT field_varchar, field_bad FROM one_row_table", net::use_future);
|
||||
validate_future_exception(fut, make_error_code(mysql::Error::bad_field_error));
|
||||
validate_async_fail(
|
||||
make_query_initiator("SELECT field_varchar, field_bad FROM one_row_table"),
|
||||
mysql::Error::bad_field_error,
|
||||
{"unknown column", "field_bad"}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -209,14 +228,17 @@ TEST_F(QueryTest, FetchOneSyncErrc_NoResults)
|
||||
EXPECT_EQ(result.fields().size(), 2);
|
||||
|
||||
// Already in the end of the resultset, we receive the EOF
|
||||
const mysql::row* row = result.fetch_one(errc);
|
||||
const mysql::row* row = result.fetch_one(errc, info);
|
||||
EXPECT_EQ(errc, mysql::error_code());
|
||||
EXPECT_EQ(info, error_info());
|
||||
EXPECT_EQ(row, nullptr);
|
||||
validate_eof(result);
|
||||
|
||||
// Fetching again just returns null
|
||||
row = result.fetch_one(errc);
|
||||
reset_errors();
|
||||
row = result.fetch_one(errc, info);
|
||||
EXPECT_EQ(errc, mysql::error_code());
|
||||
EXPECT_EQ(info, error_info());
|
||||
EXPECT_EQ(row, nullptr);
|
||||
validate_eof(result);
|
||||
}
|
||||
@@ -229,16 +251,19 @@ TEST_F(QueryTest, FetchOneSyncErrc_OneRow)
|
||||
EXPECT_EQ(result.fields().size(), 2);
|
||||
|
||||
// Fetch only row
|
||||
const mysql::row* row = result.fetch_one(errc);
|
||||
const mysql::row* row = result.fetch_one(errc, info);
|
||||
ASSERT_EQ(errc, mysql::error_code());
|
||||
EXPECT_EQ(info, error_info());
|
||||
ASSERT_NE(row, nullptr);
|
||||
validate_2fields_meta(result, "one_row_table");
|
||||
EXPECT_EQ(row->values(), makevalues(1, "f0"));
|
||||
EXPECT_FALSE(result.complete());
|
||||
|
||||
// Fetch next: end of resultset
|
||||
row = result.fetch_one(errc);
|
||||
reset_errors();
|
||||
row = result.fetch_one(errc, info);
|
||||
ASSERT_EQ(errc, mysql::error_code());
|
||||
EXPECT_EQ(info, error_info());
|
||||
ASSERT_EQ(row, nullptr);
|
||||
validate_eof(result);
|
||||
}
|
||||
@@ -251,24 +276,29 @@ TEST_F(QueryTest, FetchOneSyncErrc_TwoRows)
|
||||
EXPECT_EQ(result.fields().size(), 2);
|
||||
|
||||
// Fetch first row
|
||||
const mysql::row* row = result.fetch_one(errc);
|
||||
const mysql::row* row = result.fetch_one(errc, info);
|
||||
ASSERT_EQ(errc, mysql::error_code());
|
||||
EXPECT_EQ(info, error_info());
|
||||
ASSERT_NE(row, nullptr);
|
||||
validate_2fields_meta(result, "two_rows_table");
|
||||
EXPECT_EQ(row->values(), makevalues(1, "f0"));
|
||||
EXPECT_FALSE(result.complete());
|
||||
|
||||
// Fetch next row
|
||||
row = result.fetch_one(errc);
|
||||
reset_errors();
|
||||
row = result.fetch_one(errc, info);
|
||||
ASSERT_EQ(errc, mysql::error_code());
|
||||
EXPECT_EQ(info, error_info());
|
||||
ASSERT_NE(row, nullptr);
|
||||
validate_2fields_meta(result, "two_rows_table");
|
||||
EXPECT_EQ(row->values(), makevalues(2, "f1"));
|
||||
EXPECT_FALSE(result.complete());
|
||||
|
||||
// Fetch next: end of resultset
|
||||
row = result.fetch_one(errc);
|
||||
reset_errors();
|
||||
row = result.fetch_one(errc, info);
|
||||
ASSERT_EQ(errc, mysql::error_code());
|
||||
EXPECT_EQ(info, error_info());
|
||||
ASSERT_EQ(row, nullptr);
|
||||
validate_eof(result);
|
||||
}
|
||||
@@ -309,12 +339,14 @@ TEST_F(QueryTest, FetchOneAsync_NoResults)
|
||||
auto result = conn.query("SELECT * FROM empty_table");
|
||||
|
||||
// Already in the end of the resultset, we receive the EOF
|
||||
const auto* row = result.async_fetch_one(net::use_future).get();
|
||||
auto [info, row] = result.async_fetch_one(net::use_future).get();
|
||||
EXPECT_EQ(info, error_info());
|
||||
EXPECT_EQ(row, nullptr);
|
||||
validate_eof(result);
|
||||
|
||||
// Fetching again just returns null
|
||||
row = result.async_fetch_one(net::use_future).get();
|
||||
std::tie(info, row) = result.async_fetch_one(net::use_future).get();
|
||||
EXPECT_EQ(info, error_info());
|
||||
EXPECT_EQ(row, nullptr);
|
||||
validate_eof(result);
|
||||
}
|
||||
@@ -324,13 +356,16 @@ TEST_F(QueryTest, FetchOneAsync_OneRow)
|
||||
auto result = conn.query("SELECT * FROM one_row_table");
|
||||
|
||||
// Fetch only row
|
||||
const auto* row = result.async_fetch_one(net::use_future).get();
|
||||
auto [info, row] = result.async_fetch_one(net::use_future).get();
|
||||
EXPECT_EQ(info, error_info());
|
||||
ASSERT_NE(row, nullptr);
|
||||
EXPECT_EQ(row->values(), makevalues(1, "f0"));
|
||||
EXPECT_FALSE(result.complete());
|
||||
|
||||
// Fetch next: end of resultset
|
||||
row = result.async_fetch_one(net::use_future).get();
|
||||
reset_errors();
|
||||
std::tie(info, row) = result.async_fetch_one(net::use_future).get();
|
||||
EXPECT_EQ(info, error_info());
|
||||
ASSERT_EQ(row, nullptr);
|
||||
validate_eof(result);
|
||||
}
|
||||
@@ -340,19 +375,24 @@ TEST_F(QueryTest, FetchOneAsync_TwoRows)
|
||||
auto result = conn.query("SELECT * FROM two_rows_table");
|
||||
|
||||
// Fetch first row
|
||||
const auto* row = result.async_fetch_one(net::use_future).get();
|
||||
auto [info, row] = result.async_fetch_one(net::use_future).get();
|
||||
EXPECT_EQ(info, error_info());
|
||||
ASSERT_NE(row, nullptr);
|
||||
EXPECT_EQ(row->values(), makevalues(1, "f0"));
|
||||
EXPECT_FALSE(result.complete());
|
||||
|
||||
// Fetch next row
|
||||
row = result.async_fetch_one(net::use_future).get();
|
||||
reset_errors();
|
||||
std::tie(info, row) = result.async_fetch_one(net::use_future).get();
|
||||
EXPECT_EQ(info, error_info());
|
||||
ASSERT_NE(row, nullptr);
|
||||
EXPECT_EQ(row->values(), makevalues(2, "f1"));
|
||||
EXPECT_FALSE(result.complete());
|
||||
|
||||
// Fetch next: end of resultset
|
||||
row = result.async_fetch_one(net::use_future).get();
|
||||
reset_errors();
|
||||
std::tie(info, row) = result.async_fetch_one(net::use_future).get();
|
||||
EXPECT_EQ(info, error_info());
|
||||
ASSERT_EQ(row, nullptr);
|
||||
validate_eof(result);
|
||||
}
|
||||
@@ -363,15 +403,18 @@ TEST_F(QueryTest, FetchManySyncErrc_NoResults)
|
||||
auto result = conn.query("SELECT * FROM empty_table");
|
||||
|
||||
// Fetch many, but there are no results
|
||||
auto rows = result.fetch_many(10, errc);
|
||||
auto rows = result.fetch_many(10, errc, info);
|
||||
ASSERT_EQ(errc, error_code());
|
||||
EXPECT_EQ(info, error_info());
|
||||
EXPECT_TRUE(rows.empty());
|
||||
EXPECT_TRUE(result.complete());
|
||||
validate_eof(result);
|
||||
|
||||
// Fetch again, should return OK and empty
|
||||
rows = result.fetch_many(10, errc);
|
||||
reset_errors();
|
||||
rows = result.fetch_many(10, errc, info);
|
||||
ASSERT_EQ(errc, error_code());
|
||||
EXPECT_EQ(info, error_info());
|
||||
EXPECT_TRUE(rows.empty());
|
||||
EXPECT_TRUE(result.complete());
|
||||
validate_eof(result);
|
||||
@@ -382,14 +425,17 @@ TEST_F(QueryTest, FetchManySyncErrc_MoreRowsThanCount)
|
||||
auto result = conn.query("SELECT * FROM three_rows_table");
|
||||
|
||||
// Fetch 2, one remaining
|
||||
auto rows = result.fetch_many(2, errc);
|
||||
auto rows = result.fetch_many(2, errc, info);
|
||||
ASSERT_EQ(errc, error_code());
|
||||
EXPECT_EQ(info, error_info());
|
||||
EXPECT_FALSE(result.complete());
|
||||
EXPECT_EQ(rows, (makerows(2, 1, "f0", 2, "f1")));
|
||||
|
||||
// Fetch another two (completes the resultset)
|
||||
rows = result.fetch_many(2, errc);
|
||||
reset_errors();
|
||||
rows = result.fetch_many(2, errc, info);
|
||||
ASSERT_EQ(errc, error_code());
|
||||
EXPECT_EQ(info, error_info());
|
||||
EXPECT_TRUE(result.complete());
|
||||
validate_eof(result);
|
||||
EXPECT_EQ(rows, (makerows(2, 3, "f2")));
|
||||
@@ -400,8 +446,9 @@ TEST_F(QueryTest, FetchManySyncErrc_LessRowsThanCount)
|
||||
auto result = conn.query("SELECT * FROM two_rows_table");
|
||||
|
||||
// Fetch 3, resultset exhausted
|
||||
auto rows = result.fetch_many(3, errc);
|
||||
auto rows = result.fetch_many(3, errc, info);
|
||||
ASSERT_EQ(errc, error_code());
|
||||
EXPECT_EQ(info, error_info());
|
||||
EXPECT_EQ(rows, (makerows(2, 1, "f0", 2, "f1")));
|
||||
validate_eof(result);
|
||||
}
|
||||
@@ -411,14 +458,17 @@ TEST_F(QueryTest, FetchManySyncErrc_SameRowsAsCount)
|
||||
auto result = conn.query("SELECT * FROM two_rows_table");
|
||||
|
||||
// Fetch 2, 0 remaining but resultset not exhausted
|
||||
auto rows = result.fetch_many(2, errc);
|
||||
auto rows = result.fetch_many(2, errc, info);
|
||||
ASSERT_EQ(errc, error_code());
|
||||
EXPECT_EQ(info, error_info());
|
||||
EXPECT_FALSE(result.complete());
|
||||
EXPECT_EQ(rows, (makerows(2, 1, "f0", 2, "f1")));
|
||||
|
||||
// Fetch again, exhausts the resultset
|
||||
rows = result.fetch_many(2, errc);
|
||||
reset_errors();
|
||||
rows = result.fetch_many(2, errc, info);
|
||||
ASSERT_EQ(errc, error_code());
|
||||
EXPECT_EQ(info, error_info());
|
||||
EXPECT_EQ(rows.size(), 0);
|
||||
validate_eof(result);
|
||||
}
|
||||
@@ -428,8 +478,9 @@ TEST_F(QueryTest, FetchManySyncErrc_CountEqualsOne)
|
||||
auto result = conn.query("SELECT * FROM one_row_table");
|
||||
|
||||
// Fetch 1, 1 remaining
|
||||
auto rows = result.fetch_many(1, errc);
|
||||
auto rows = result.fetch_many(1, errc, info);
|
||||
ASSERT_EQ(errc, error_code());
|
||||
EXPECT_EQ(info, error_info());
|
||||
EXPECT_FALSE(result.complete());
|
||||
EXPECT_EQ(rows, (makerows(2, 1, "f0")));
|
||||
}
|
||||
@@ -460,13 +511,16 @@ TEST_F(QueryTest, FetchManyAsync_NoResults)
|
||||
auto result = conn.query("SELECT * FROM empty_table");
|
||||
|
||||
// Fetch many, but there are no results
|
||||
auto rows = result.async_fetch_many(10, net::use_future).get();
|
||||
auto [info, rows] = result.async_fetch_many(10, net::use_future).get();
|
||||
EXPECT_EQ(info, error_info());
|
||||
EXPECT_TRUE(rows.empty());
|
||||
EXPECT_TRUE(result.complete());
|
||||
validate_eof(result);
|
||||
|
||||
// Fetch again, should return OK and empty
|
||||
rows = result.async_fetch_many(10, net::use_future).get();
|
||||
reset_errors();
|
||||
std::tie(info, rows) = result.async_fetch_many(10, net::use_future).get();
|
||||
EXPECT_EQ(info, error_info());
|
||||
EXPECT_TRUE(rows.empty());
|
||||
EXPECT_TRUE(result.complete());
|
||||
validate_eof(result);
|
||||
@@ -477,12 +531,14 @@ TEST_F(QueryTest, FetchManyAsync_MoreRowsThanCount)
|
||||
auto result = conn.query("SELECT * FROM three_rows_table");
|
||||
|
||||
// Fetch 2, one remaining
|
||||
auto rows = result.async_fetch_many(2, net::use_future).get();
|
||||
auto [info, rows] = result.async_fetch_many(2, net::use_future).get();
|
||||
EXPECT_EQ(info, error_info());
|
||||
EXPECT_FALSE(result.complete());
|
||||
EXPECT_EQ(rows, (makerows(2, 1, "f0", 2, "f1")));
|
||||
|
||||
// Fetch another two (completes the resultset)
|
||||
rows = result.async_fetch_many(2, net::use_future).get();
|
||||
std::tie(info, rows) = result.async_fetch_many(2, net::use_future).get();
|
||||
EXPECT_EQ(info, error_info());
|
||||
EXPECT_TRUE(result.complete());
|
||||
validate_eof(result);
|
||||
EXPECT_EQ(rows, (makerows(2, 3, "f2")));
|
||||
@@ -493,7 +549,8 @@ TEST_F(QueryTest, FetchManyAsync_LessRowsThanCount)
|
||||
auto result = conn.query("SELECT * FROM two_rows_table");
|
||||
|
||||
// Fetch 3, resultset exhausted
|
||||
auto rows = result.async_fetch_many(3, net::use_future).get();
|
||||
auto [info, rows] = result.async_fetch_many(3, net::use_future).get();
|
||||
EXPECT_EQ(info, error_info());
|
||||
EXPECT_EQ(rows, (makerows(2, 1, "f0", 2, "f1")));
|
||||
validate_eof(result);
|
||||
}
|
||||
@@ -503,12 +560,15 @@ TEST_F(QueryTest, FetchManyAsync_SameRowsAsCount)
|
||||
auto result = conn.query("SELECT * FROM two_rows_table");
|
||||
|
||||
// Fetch 2, 0 remaining but resultset not exhausted
|
||||
auto rows = result.async_fetch_many(2, net::use_future).get();
|
||||
auto [info, rows] = result.async_fetch_many(2, net::use_future).get();
|
||||
EXPECT_EQ(info, error_info());
|
||||
EXPECT_FALSE(result.complete());
|
||||
EXPECT_EQ(rows, (makerows(2, 1, "f0", 2, "f1")));
|
||||
|
||||
// Fetch again, exhausts the resultset
|
||||
rows = result.async_fetch_many(2, net::use_future).get();
|
||||
reset_errors();
|
||||
std::tie(info, rows) = result.async_fetch_many(2, net::use_future).get();
|
||||
EXPECT_EQ(info, error_info());
|
||||
EXPECT_EQ(rows.size(), 0);
|
||||
validate_eof(result);
|
||||
}
|
||||
@@ -518,7 +578,8 @@ TEST_F(QueryTest, FetchManyAsync_CountEqualsOne)
|
||||
auto result = conn.query("SELECT * FROM one_row_table");
|
||||
|
||||
// Fetch 1, 1 remaining
|
||||
auto rows = result.async_fetch_many(1, net::use_future).get();
|
||||
auto [info, rows] = result.async_fetch_many(1, net::use_future).get();
|
||||
EXPECT_EQ(info, error_info());
|
||||
EXPECT_FALSE(result.complete());
|
||||
EXPECT_EQ(rows, (makerows(2, 1, "f0")));
|
||||
}
|
||||
@@ -529,14 +590,17 @@ TEST_F(QueryTest, FetchAllSyncErrc_NoResults)
|
||||
auto result = conn.query("SELECT * FROM empty_table");
|
||||
|
||||
// Fetch many, but there are no results
|
||||
auto rows = result.fetch_all(errc);
|
||||
auto rows = result.fetch_all(errc, info);
|
||||
ASSERT_EQ(errc, error_code());
|
||||
EXPECT_EQ(info, error_info());
|
||||
EXPECT_TRUE(rows.empty());
|
||||
EXPECT_TRUE(result.complete());
|
||||
|
||||
// Fetch again, should return OK and empty
|
||||
rows = result.fetch_all(errc);
|
||||
reset_errors();
|
||||
rows = result.fetch_all(errc, info);
|
||||
ASSERT_EQ(errc, error_code());
|
||||
EXPECT_EQ(info, error_info());
|
||||
EXPECT_TRUE(rows.empty());
|
||||
validate_eof(result);
|
||||
}
|
||||
@@ -545,8 +609,9 @@ TEST_F(QueryTest, FetchAllSyncErrc_OneRow)
|
||||
{
|
||||
auto result = conn.query("SELECT * FROM one_row_table");
|
||||
|
||||
auto rows = result.fetch_all(errc);
|
||||
auto rows = result.fetch_all(errc, info);
|
||||
ASSERT_EQ(errc, error_code());
|
||||
EXPECT_EQ(info, error_info());
|
||||
EXPECT_TRUE(result.complete());
|
||||
EXPECT_EQ(rows, (makerows(2, 1, "f0")));
|
||||
}
|
||||
@@ -555,8 +620,9 @@ TEST_F(QueryTest, FetchAllSyncErrc_SeveralRows)
|
||||
{
|
||||
auto result = conn.query("SELECT * FROM two_rows_table");
|
||||
|
||||
auto rows = result.fetch_all(errc);
|
||||
auto rows = result.fetch_all(errc, info);
|
||||
ASSERT_EQ(errc, error_code());
|
||||
EXPECT_EQ(info, error_info());
|
||||
validate_eof(result);
|
||||
EXPECT_EQ(rows, (makerows(2, 1, "f0", 2, "f1")));
|
||||
}
|
||||
@@ -578,12 +644,15 @@ TEST_F(QueryTest, FetchAllAsync_NoResults)
|
||||
auto result = conn.query("SELECT * FROM empty_table");
|
||||
|
||||
// Fetch many, but there are no results
|
||||
auto rows = result.async_fetch_all(net::use_future).get();
|
||||
auto [info, rows] = result.async_fetch_all(net::use_future).get();
|
||||
EXPECT_EQ(info, error_info());
|
||||
EXPECT_TRUE(rows.empty());
|
||||
EXPECT_TRUE(result.complete());
|
||||
|
||||
// Fetch again, should return OK and empty
|
||||
rows = result.async_fetch_all(net::use_future).get();
|
||||
reset_errors();
|
||||
std::tie(info, rows) = result.async_fetch_all(net::use_future).get();
|
||||
EXPECT_EQ(info, error_info());
|
||||
EXPECT_TRUE(rows.empty());
|
||||
validate_eof(result);
|
||||
}
|
||||
@@ -592,7 +661,8 @@ TEST_F(QueryTest, FetchAllAsync_OneRow)
|
||||
{
|
||||
auto result = conn.query("SELECT * FROM one_row_table");
|
||||
|
||||
auto rows = result.async_fetch_all(net::use_future).get();
|
||||
auto [info, rows] = result.async_fetch_all(net::use_future).get();
|
||||
EXPECT_EQ(info, error_info());
|
||||
EXPECT_TRUE(result.complete());
|
||||
EXPECT_EQ(rows, (makerows(2, 1, "f0")));
|
||||
}
|
||||
@@ -601,7 +671,8 @@ TEST_F(QueryTest, FetchAllAsync_SeveralRows)
|
||||
{
|
||||
auto result = conn.query("SELECT * FROM two_rows_table");
|
||||
|
||||
auto rows = result.async_fetch_all(net::use_future).get();
|
||||
auto [info, rows] = result.async_fetch_all(net::use_future).get();
|
||||
EXPECT_EQ(info, error_info());
|
||||
validate_eof(result);
|
||||
EXPECT_EQ(rows, (makerows(2, 1, "f0", 2, "f1")));
|
||||
}
|
||||
@@ -616,8 +687,3 @@ TEST_F(QueryTest, QueryAndFetch_AliasedTableAndField_MetadataCorrect)
|
||||
}
|
||||
|
||||
} // anon namespace
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -4,5 +4,9 @@ set -e
|
||||
|
||||
SCRIPTPATH="$( cd "$(dirname "$0")" ; pwd -P )"
|
||||
|
||||
mysql -u root < $SCRIPTPATH/db_setup.sql
|
||||
if [ "$MYSQL_SKIP_DB_SETUP" != "1" ]
|
||||
then
|
||||
mysql -u root < $SCRIPTPATH/db_setup.sql
|
||||
fi
|
||||
|
||||
./mysql_integrationtests
|
||||
Reference in New Issue
Block a user