mirror of
https://github.com/boostorg/mysql.git
synced 2026-02-14 12:52:17 +00:00
333 lines
9.2 KiB
C++
333 lines
9.2 KiB
C++
//
|
|
// 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)
|
|
//
|
|
|
|
#include <boost/mysql/buffer_params.hpp>
|
|
#include <boost/mysql/resultset_base.hpp>
|
|
#include <boost/mysql/row_view.hpp>
|
|
|
|
#include <boost/test/unit_test.hpp>
|
|
|
|
#include "er_connection.hpp"
|
|
#include "er_network_variant.hpp"
|
|
#include "er_resultset.hpp"
|
|
#include "integration_test_common.hpp"
|
|
#include "test_common.hpp"
|
|
|
|
using namespace boost::mysql::test;
|
|
using boost::mysql::error_code;
|
|
using boost::mysql::row;
|
|
using boost::mysql::row_view;
|
|
|
|
namespace {
|
|
|
|
BOOST_AUTO_TEST_SUITE(test_resultset)
|
|
|
|
void validate_eof(
|
|
const er_resultset& result,
|
|
unsigned affected_rows = 0,
|
|
unsigned warnings = 0,
|
|
unsigned last_insert = 0,
|
|
boost::string_view info = ""
|
|
)
|
|
{
|
|
BOOST_TEST_REQUIRE(result.base().valid());
|
|
BOOST_TEST_REQUIRE(result.base().complete());
|
|
BOOST_TEST(result.base().affected_rows() == affected_rows);
|
|
BOOST_TEST(result.base().warning_count() == warnings);
|
|
BOOST_TEST(result.base().last_insert_id() == last_insert);
|
|
BOOST_TEST(result.base().info() == info);
|
|
}
|
|
|
|
// Interface to generate a resultset
|
|
class resultset_generator
|
|
{
|
|
public:
|
|
virtual ~resultset_generator() {}
|
|
virtual const char* name() const = 0;
|
|
virtual void generate(er_connection&, er_resultset&, boost::string_view) = 0;
|
|
};
|
|
|
|
class text_resultset_generator : public resultset_generator
|
|
{
|
|
public:
|
|
const char* name() const override { return "text"; }
|
|
void generate(er_connection& conn, er_resultset& output, boost::string_view query) override
|
|
{
|
|
conn.query(query, output).validate_no_error();
|
|
}
|
|
};
|
|
|
|
class binary_resultset_generator : public resultset_generator
|
|
{
|
|
public:
|
|
const char* name() const override { return "binary"; }
|
|
void generate(er_connection& conn, er_resultset& output, boost::string_view query) override
|
|
{
|
|
auto stmt = conn.variant().create_statement();
|
|
conn.prepare_statement(query, *stmt).validate_no_error();
|
|
stmt->execute_collection({}, output).validate_no_error();
|
|
}
|
|
};
|
|
|
|
static text_resultset_generator text_obj;
|
|
static binary_resultset_generator binary_obj;
|
|
|
|
// Sample type
|
|
struct resultset_sample : network_sample
|
|
{
|
|
resultset_generator* gen;
|
|
|
|
resultset_sample(er_network_variant* net, resultset_generator* gen)
|
|
: network_sample(net), gen(gen)
|
|
{
|
|
}
|
|
};
|
|
|
|
std::ostream& operator<<(std::ostream& os, const resultset_sample& input)
|
|
{
|
|
return os << static_cast<const network_sample&>(input) << '_' << input.gen->name();
|
|
}
|
|
|
|
resultset_sample net_samples[] = {
|
|
resultset_sample(get_variant("tcp_sync_errc"), &text_obj),
|
|
resultset_sample(get_variant("tcp_async_callback"), &text_obj),
|
|
resultset_sample(get_variant("tcp_sync_exc"), &binary_obj),
|
|
resultset_sample(get_variant("tcp_async_callback_noerrinfo"), &binary_obj),
|
|
};
|
|
|
|
struct resultset_fixture : network_fixture
|
|
{
|
|
resultset_generator* gen;
|
|
|
|
void setup_and_connect(const resultset_sample& sample)
|
|
{
|
|
network_fixture::setup_and_connect(sample.net);
|
|
gen = sample.gen;
|
|
}
|
|
|
|
void generate(boost::string_view query)
|
|
{
|
|
assert(gen);
|
|
return gen->generate(*conn, *result, query);
|
|
}
|
|
};
|
|
|
|
BOOST_AUTO_TEST_SUITE(read_one)
|
|
|
|
BOOST_MYSQL_NETWORK_TEST(no_results, resultset_fixture, net_samples)
|
|
{
|
|
setup_and_connect(sample);
|
|
generate("SELECT * FROM empty_table");
|
|
BOOST_TEST(result->base().valid());
|
|
BOOST_TEST(!result->base().complete());
|
|
BOOST_TEST(result->base().meta().size() == 2u);
|
|
|
|
// Already in the end of the resultset, we receive the EOF
|
|
row_view r = result->read_one().get();
|
|
BOOST_TEST(r == row_view());
|
|
validate_eof(*result);
|
|
|
|
// Reading again does nothing
|
|
r = result->read_one().get();
|
|
BOOST_TEST(r == row_view());
|
|
validate_eof(*result);
|
|
}
|
|
|
|
BOOST_MYSQL_NETWORK_TEST(one_row, resultset_fixture, net_samples)
|
|
{
|
|
setup_and_connect(sample);
|
|
generate("SELECT * FROM one_row_table");
|
|
BOOST_TEST(result->base().valid());
|
|
BOOST_TEST(!result->base().complete());
|
|
BOOST_TEST(result->base().meta().size() == 2u);
|
|
|
|
// Read the only row
|
|
row_view r = result->read_one().get();
|
|
validate_2fields_meta(result->base(), "one_row_table");
|
|
BOOST_TEST((r == makerow(1, "f0")));
|
|
BOOST_TEST(!result->base().complete());
|
|
|
|
// Read next: end of resultset_base
|
|
r = result->read_one().get();
|
|
BOOST_TEST(r == row());
|
|
validate_eof(*result);
|
|
}
|
|
|
|
BOOST_MYSQL_NETWORK_TEST(two_rows, resultset_fixture, net_samples)
|
|
{
|
|
setup_and_connect(sample);
|
|
generate("SELECT * FROM two_rows_table");
|
|
BOOST_TEST(result->base().valid());
|
|
BOOST_TEST(!result->base().complete());
|
|
BOOST_TEST(result->base().meta().size() == 2u);
|
|
|
|
// Read first row
|
|
row_view r = result->read_one().get();
|
|
validate_2fields_meta(result->base(), "two_rows_table");
|
|
BOOST_TEST((r == makerow(1, "f0")));
|
|
BOOST_TEST(!result->base().complete());
|
|
|
|
// Read next row
|
|
r = result->read_one().get();
|
|
validate_2fields_meta(result->base(), "two_rows_table");
|
|
BOOST_TEST((r == makerow(2, "f1")));
|
|
BOOST_TEST(!result->base().complete());
|
|
|
|
// Read next: end of resultset_base
|
|
r = result->read_one().get();
|
|
BOOST_TEST(r == row());
|
|
validate_eof(*result);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_SUITE_END() // read_one
|
|
|
|
BOOST_AUTO_TEST_SUITE(read_some)
|
|
|
|
BOOST_MYSQL_NETWORK_TEST(no_results, resultset_fixture, net_samples)
|
|
{
|
|
setup_and_connect(sample);
|
|
generate("SELECT * FROM empty_table");
|
|
|
|
// Read, but there are no results
|
|
auto rows = result->read_some().get();
|
|
BOOST_TEST(rows.empty());
|
|
validate_eof(*result);
|
|
|
|
// Read again, should return OK and empty
|
|
rows = result->read_some().get();
|
|
BOOST_TEST(rows.empty());
|
|
validate_eof(*result);
|
|
}
|
|
|
|
BOOST_MYSQL_NETWORK_TEST(one_row, resultset_fixture, net_samples)
|
|
{
|
|
setup_and_connect(sample);
|
|
generate("SELECT * FROM one_row_table");
|
|
|
|
// Read once. The resultset may or may not be complete, depending
|
|
// on how the buffer reallocated memory
|
|
auto rows = result->read_some().get();
|
|
BOOST_TEST((rows == makerows(2, 1, "f0")));
|
|
|
|
// Reading again should complete the resultset
|
|
rows = result->read_some().get();
|
|
BOOST_TEST(rows.empty());
|
|
validate_eof(*result);
|
|
|
|
// Reading again does nothing
|
|
rows = result->read_some().get();
|
|
BOOST_TEST(rows.empty());
|
|
validate_eof(*result);
|
|
}
|
|
|
|
BOOST_MYSQL_NETWORK_TEST(several_rows, resultset_fixture, net_samples)
|
|
{
|
|
setup_and_connect(sample);
|
|
generate("SELECT * FROM three_rows_table");
|
|
|
|
// We don't know how many rows there will be in each batch,
|
|
// but they will come in order
|
|
std::size_t call_count = 0;
|
|
std::vector<row> all_rows;
|
|
while (!result->base().complete() && call_count <= 4)
|
|
{
|
|
++call_count;
|
|
for (row_view rv : result->read_some().get())
|
|
all_rows.emplace_back(rv);
|
|
}
|
|
|
|
// Verify rows
|
|
BOOST_TEST_REQUIRE(all_rows.size() == 3);
|
|
BOOST_TEST(all_rows[0] == makerow(1, "f0"));
|
|
BOOST_TEST(all_rows[1] == makerow(2, "f1"));
|
|
BOOST_TEST(all_rows[2] == makerow(3, "f2"));
|
|
|
|
// Verify eof
|
|
validate_eof(*result);
|
|
|
|
// Reading again does nothing
|
|
auto rows = result->read_some().get();
|
|
BOOST_TEST(rows.empty());
|
|
validate_eof(*result);
|
|
}
|
|
|
|
BOOST_MYSQL_NETWORK_TEST(several_rows_single_read, resultset_fixture, net_samples)
|
|
{
|
|
// make sure the entire result can be read at once
|
|
params.set_buffer_config(boost::mysql::buffer_params(4096));
|
|
setup_and_connect(sample);
|
|
generate("SELECT * FROM three_rows_table");
|
|
|
|
// Read
|
|
auto rows = result->read_some().get();
|
|
BOOST_TEST(rows == makerows(2, 1, "f0", 2, "f1", 3, "f2"));
|
|
validate_eof(*result);
|
|
|
|
// Reading again does nothing
|
|
rows = result->read_some().get();
|
|
BOOST_TEST(rows.empty());
|
|
validate_eof(*result);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_SUITE_END() // read_many
|
|
|
|
BOOST_AUTO_TEST_SUITE(read_all)
|
|
|
|
BOOST_MYSQL_NETWORK_TEST(no_results, resultset_fixture, net_samples)
|
|
{
|
|
setup_and_connect(sample);
|
|
generate("SELECT * FROM empty_table");
|
|
|
|
// Read all
|
|
auto rows = result->read_all().get();
|
|
BOOST_TEST(rows.empty());
|
|
validate_eof(*result);
|
|
|
|
// Read again, should return OK and empty
|
|
rows = result->read_all().get();
|
|
BOOST_TEST(rows.empty());
|
|
validate_eof(*result);
|
|
}
|
|
|
|
BOOST_MYSQL_NETWORK_TEST(one_row, resultset_fixture, net_samples)
|
|
{
|
|
setup_and_connect(sample);
|
|
generate("SELECT * FROM one_row_table");
|
|
|
|
// Read all
|
|
auto rows = result->read_all().get();
|
|
BOOST_TEST(rows == makerows(2, 1, "f0"));
|
|
validate_eof(*result);
|
|
|
|
// Reading again does nothing
|
|
rows = result->read_all().get();
|
|
BOOST_TEST(rows.empty());
|
|
validate_eof(*result);
|
|
}
|
|
|
|
BOOST_MYSQL_NETWORK_TEST(several_rows, resultset_fixture, net_samples)
|
|
{
|
|
setup_and_connect(sample);
|
|
generate("SELECT * FROM two_rows_table");
|
|
|
|
// Read all
|
|
auto rows = result->read_all().get();
|
|
BOOST_TEST(rows == makerows(2, 1, "f0", 2, "f1"));
|
|
validate_eof(*result);
|
|
|
|
// Reading again does nothing
|
|
rows = result->read_all().get();
|
|
BOOST_TEST(rows.empty());
|
|
validate_eof(*result);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_SUITE_END() // read_all
|
|
|
|
BOOST_AUTO_TEST_SUITE_END() // test_resultset
|
|
|
|
} // namespace
|