Added thirdparty: boost library

This commit is contained in:
Viacheslav Demydiuk
2024-01-06 19:55:56 +02:00
parent bf49f439e1
commit bccd1e7051
15683 changed files with 3239840 additions and 0 deletions
@@ -0,0 +1,217 @@
//
// Copyright (c) 2019-2023 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_DETAIL_EXECUTION_PROCESSOR_EXECUTION_PROCESSOR_HPP
#define BOOST_MYSQL_DETAIL_EXECUTION_PROCESSOR_EXECUTION_PROCESSOR_HPP
#include <boost/mysql/diagnostics.hpp>
#include <boost/mysql/error_code.hpp>
#include <boost/mysql/field_view.hpp>
#include <boost/mysql/metadata.hpp>
#include <boost/mysql/metadata_mode.hpp>
#include <boost/mysql/string_view.hpp>
#include <boost/mysql/detail/access.hpp>
#include <boost/mysql/detail/coldef_view.hpp>
#include <boost/mysql/detail/ok_view.hpp>
#include <boost/mysql/detail/resultset_encoding.hpp>
#include <boost/assert.hpp>
#include <boost/config.hpp>
#include <boost/core/span.hpp>
#include <cstddef>
#include <cstdint>
#include <limits>
namespace boost {
namespace mysql {
namespace detail {
// A type-erased reference to be used as the output range for static_execution_state
class output_ref
{
// Pointer to the first element of the span
void* data_{};
// Number of elements in the span
std::size_t max_size_{(std::numeric_limits<std::size_t>::max)()};
// Identifier for the type of elements. Index in the resultset type list
std::size_t type_index_{};
// Offset into the span's data (static_execution_state). Otherwise unused
std::size_t offset_{};
public:
constexpr output_ref() noexcept = default;
template <class T>
constexpr output_ref(boost::span<T> span, std::size_t type_index, std::size_t offset = 0) noexcept
: data_(span.data()), max_size_(span.size()), type_index_(type_index), offset_(offset)
{
}
std::size_t max_size() const noexcept { return max_size_; }
std::size_t type_index() const noexcept { return type_index_; }
std::size_t offset() const noexcept { return offset_; }
void set_offset(std::size_t v) noexcept { offset_ = v; }
template <class T>
T& span_element() const noexcept
{
BOOST_ASSERT(data_);
return static_cast<T*>(data_)[offset_];
}
};
class execution_processor
{
public:
virtual ~execution_processor() {}
void reset(resultset_encoding enc, metadata_mode mode) noexcept
{
state_ = state_t::reading_first;
encoding_ = enc;
mode_ = mode;
seqnum_ = 0;
remaining_meta_ = 0;
reset_impl();
}
BOOST_ATTRIBUTE_NODISCARD
error_code on_head_ok_packet(const ok_view& pack, diagnostics& diag)
{
BOOST_ASSERT(is_reading_head());
auto err = on_head_ok_packet_impl(pack, diag);
set_state_for_ok(pack);
return err;
}
void on_num_meta(std::size_t num_columns)
{
BOOST_ASSERT(is_reading_head());
on_num_meta_impl(num_columns);
remaining_meta_ = num_columns;
set_state(state_t::reading_metadata);
}
BOOST_ATTRIBUTE_NODISCARD
error_code on_meta(const coldef_view& pack, diagnostics& diag)
{
BOOST_ASSERT(is_reading_meta());
bool is_last = --remaining_meta_ == 0;
auto err = on_meta_impl(pack, is_last, diag);
if (is_last)
set_state(state_t::reading_rows);
return err;
}
void on_row_batch_start()
{
BOOST_ASSERT(is_reading_rows());
on_row_batch_start_impl();
}
void on_row_batch_finish() { on_row_batch_finish_impl(); }
BOOST_ATTRIBUTE_NODISCARD
error_code on_row(span<const std::uint8_t> msg, const output_ref& ref, std::vector<field_view>& storage)
{
BOOST_ASSERT(is_reading_rows());
return on_row_impl(msg, ref, storage);
}
BOOST_ATTRIBUTE_NODISCARD
error_code on_row_ok_packet(const ok_view& pack)
{
BOOST_ASSERT(is_reading_rows());
auto err = on_row_ok_packet_impl(pack);
set_state_for_ok(pack);
return err;
}
bool is_reading_first() const noexcept { return state_ == state_t::reading_first; }
bool is_reading_first_subseq() const noexcept { return state_ == state_t::reading_first_subseq; }
bool is_reading_head() const noexcept
{
return state_ == state_t::reading_first || state_ == state_t::reading_first_subseq;
}
bool is_reading_meta() const noexcept { return state_ == state_t::reading_metadata; }
bool is_reading_rows() const noexcept { return state_ == state_t::reading_rows; }
bool is_complete() const noexcept { return state_ == state_t::complete; }
resultset_encoding encoding() const noexcept { return encoding_; }
std::uint8_t& sequence_number() noexcept { return seqnum_; }
metadata_mode meta_mode() const noexcept { return mode_; }
protected:
virtual void reset_impl() noexcept = 0;
virtual error_code on_head_ok_packet_impl(const ok_view& pack, diagnostics& diag) = 0;
virtual void on_num_meta_impl(std::size_t num_columns) = 0;
virtual error_code on_meta_impl(const coldef_view& coldef, bool is_last, diagnostics& diag) = 0;
virtual error_code on_row_ok_packet_impl(const ok_view& pack) = 0;
virtual error_code on_row_impl(
span<const std::uint8_t> msg,
const output_ref& ref,
std::vector<field_view>& storage
) = 0;
virtual void on_row_batch_start_impl() = 0;
virtual void on_row_batch_finish_impl() = 0;
metadata create_meta(const coldef_view& coldef) const
{
return access::construct<metadata>(coldef, mode_ == metadata_mode::full);
}
private:
enum class state_t
{
// waiting for 1st packet, for the 1st resultset
reading_first,
// same, but for subsequent resultsets (distiguised to provide a cleaner xp to
// the user in (static_)execution_state)
reading_first_subseq,
// waiting for metadata packets
reading_metadata,
// waiting for rows
reading_rows,
// done
complete
};
state_t state_{state_t::reading_first};
resultset_encoding encoding_{resultset_encoding::text};
std::uint8_t seqnum_{};
metadata_mode mode_{metadata_mode::minimal};
std::size_t remaining_meta_{};
void set_state(state_t v) noexcept { state_ = v; }
void set_state_for_ok(const ok_view& pack) noexcept
{
if (pack.more_results())
{
set_state(state_t::reading_first_subseq);
}
else
{
set_state(state_t::complete);
}
}
};
} // namespace detail
} // namespace mysql
} // namespace boost
#endif
@@ -0,0 +1,123 @@
//
// Copyright (c) 2019-2023 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_DETAIL_EXECUTION_PROCESSOR_EXECUTION_STATE_IMPL_HPP
#define BOOST_MYSQL_DETAIL_EXECUTION_PROCESSOR_EXECUTION_STATE_IMPL_HPP
#include <boost/mysql/diagnostics.hpp>
#include <boost/mysql/error_code.hpp>
#include <boost/mysql/field_view.hpp>
#include <boost/mysql/metadata.hpp>
#include <boost/mysql/metadata_collection_view.hpp>
#include <boost/mysql/string_view.hpp>
#include <boost/mysql/detail/config.hpp>
#include <boost/mysql/detail/execution_processor/execution_processor.hpp>
#include <boost/assert.hpp>
#include <vector>
namespace boost {
namespace mysql {
namespace detail {
class execution_state_impl final : public execution_processor
{
struct ok_data
{
bool has_value{false}; // The OK packet information is default constructed, or actual data?
std::uint64_t affected_rows{}; // OK packet data
std::uint64_t last_insert_id{}; // OK packet data
std::uint16_t warnings{}; // OK packet data
bool is_out_params{false}; // Does this resultset contain OUT param information?
};
std::vector<metadata> meta_;
ok_data eof_data_;
std::vector<char> info_;
void on_new_resultset() noexcept
{
meta_.clear();
eof_data_ = ok_data{};
info_.clear();
}
BOOST_MYSQL_DECL
void on_ok_packet_impl(const ok_view& pack);
BOOST_MYSQL_DECL
void reset_impl() noexcept override final;
BOOST_MYSQL_DECL
error_code on_head_ok_packet_impl(const ok_view& pack, diagnostics&) override final;
BOOST_MYSQL_DECL
void on_num_meta_impl(std::size_t num_columns) override final;
BOOST_MYSQL_DECL
error_code on_meta_impl(const coldef_view&, bool, diagnostics&) override final;
BOOST_MYSQL_DECL
error_code on_row_impl(span<const std::uint8_t> msg, const output_ref&, std::vector<field_view>& fields)
override final;
BOOST_MYSQL_DECL
error_code on_row_ok_packet_impl(const ok_view& pack) override final;
void on_row_batch_start_impl() noexcept override final {}
void on_row_batch_finish_impl() noexcept override final {}
public:
execution_state_impl() = default;
metadata_collection_view meta() const noexcept { return meta_; }
std::uint64_t get_affected_rows() const noexcept
{
BOOST_ASSERT(eof_data_.has_value);
return eof_data_.affected_rows;
}
std::uint64_t get_last_insert_id() const noexcept
{
BOOST_ASSERT(eof_data_.has_value);
return eof_data_.last_insert_id;
}
unsigned get_warning_count() const noexcept
{
BOOST_ASSERT(eof_data_.has_value);
return eof_data_.warnings;
}
string_view get_info() const noexcept
{
BOOST_ASSERT(eof_data_.has_value);
return string_view(info_.data(), info_.size());
}
bool get_is_out_params() const noexcept
{
BOOST_ASSERT(eof_data_.has_value);
return eof_data_.is_out_params;
}
execution_state_impl& get_interface() noexcept { return *this; }
};
} // namespace detail
} // namespace mysql
} // namespace boost
#ifdef BOOST_MYSQL_HEADER_ONLY
#include <boost/mysql/impl/execution_state_impl.ipp>
#endif
#endif
@@ -0,0 +1,219 @@
//
// Copyright (c) 2019-2023 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_DETAIL_EXECUTION_PROCESSOR_RESULTS_IMPL_HPP
#define BOOST_MYSQL_DETAIL_EXECUTION_PROCESSOR_RESULTS_IMPL_HPP
#include <boost/mysql/diagnostics.hpp>
#include <boost/mysql/error_code.hpp>
#include <boost/mysql/field_view.hpp>
#include <boost/mysql/metadata.hpp>
#include <boost/mysql/metadata_collection_view.hpp>
#include <boost/mysql/rows_view.hpp>
#include <boost/mysql/string_view.hpp>
#include <boost/mysql/detail/config.hpp>
#include <boost/mysql/detail/execution_processor/execution_processor.hpp>
#include <boost/mysql/detail/row_impl.hpp>
#include <boost/assert.hpp>
namespace boost {
namespace mysql {
namespace detail {
struct per_resultset_data
{
std::size_t num_columns{}; // Number of columns this resultset has
std::size_t meta_offset{}; // Offset into the vector of metadata
std::size_t field_offset; // Offset into the vector of fields (append mode only)
std::size_t num_rows{}; // Number of rows this resultset has (append mode only)
std::uint64_t affected_rows{}; // OK packet data
std::uint64_t last_insert_id{}; // OK packet data
std::uint16_t warnings{}; // OK packet data
std::size_t info_offset{}; // Offset into the vector of info characters
std::size_t info_size{}; // Number of characters that this resultset's info string has
bool has_ok_packet_data{false}; // The OK packet information is default constructed, or actual data?
bool is_out_params{false}; // Does this resultset contain OUT param information?
};
// A container similar to a vector with SBO. To avoid depending on Boost.Container
class resultset_container
{
bool first_has_data_{false};
per_resultset_data first_;
std::vector<per_resultset_data> rest_;
public:
resultset_container() = default;
std::size_t size() const noexcept { return !first_has_data_ ? 0 : rest_.size() + 1; }
bool empty() const noexcept { return !first_has_data_; }
void clear() noexcept
{
first_has_data_ = false;
rest_.clear();
}
per_resultset_data& operator[](std::size_t i) noexcept
{
return const_cast<per_resultset_data&>(const_cast<const resultset_container&>(*this)[i]);
}
const per_resultset_data& operator[](std::size_t i) const noexcept
{
BOOST_ASSERT(i < size());
return i == 0 ? first_ : rest_[i - 1];
}
per_resultset_data& back() noexcept
{
return const_cast<per_resultset_data&>(const_cast<const resultset_container&>(*this).back());
}
const per_resultset_data& back() const noexcept
{
BOOST_ASSERT(first_has_data_);
return rest_.empty() ? first_ : rest_.back();
}
BOOST_MYSQL_DECL per_resultset_data& emplace_back();
};
// Rows for all resultsets are stored in a single rows_impl object.
// - When a row batch is started, we record how many fields we had before the batch.
// - When rows are read, fields are allocated in the rows_impl object, then deserialized against
// the allocated storage. At this point, strings/blobs point into the connection read buffer.
// - When a row batch is finished, we copy strings/blobs into the rows_impl, then transform them
// into offsets to allow rows_impl to grow.
// - When the final OK packet is received, offsets are transformed back into views.
class results_impl final : public execution_processor
{
public:
results_impl() = default;
BOOST_MYSQL_DECL
row_view get_out_params() const noexcept;
std::size_t num_resultsets() const noexcept { return per_result_.size(); }
rows_view get_rows(std::size_t index) const noexcept
{
const auto& resultset_data = per_result_[index];
return access::construct<rows_view>(
rows_.fields().data() + resultset_data.field_offset,
resultset_data.num_rows * resultset_data.num_columns,
resultset_data.num_columns
);
}
metadata_collection_view get_meta(std::size_t index) const noexcept
{
const auto& resultset_data = get_resultset(index);
return metadata_collection_view(
meta_.data() + resultset_data.meta_offset,
resultset_data.num_columns
);
}
std::uint64_t get_affected_rows(std::size_t index) const noexcept
{
return get_resultset(index).affected_rows;
}
std::uint64_t get_last_insert_id(std::size_t index) const noexcept
{
return get_resultset(index).last_insert_id;
}
unsigned get_warning_count(std::size_t index) const noexcept { return get_resultset(index).warnings; }
string_view get_info(std::size_t index) const noexcept
{
const auto& resultset_data = get_resultset(index);
return string_view(info_.data() + resultset_data.info_offset, resultset_data.info_size);
}
bool get_is_out_params(std::size_t index) const noexcept { return get_resultset(index).is_out_params; }
results_impl& get_interface() noexcept { return *this; }
private:
// Virtual impls
BOOST_MYSQL_DECL
void reset_impl() noexcept override final;
BOOST_MYSQL_DECL
void on_num_meta_impl(std::size_t num_columns) override final;
BOOST_MYSQL_DECL
error_code on_head_ok_packet_impl(const ok_view& pack, diagnostics&) override final;
BOOST_MYSQL_DECL
error_code on_meta_impl(const coldef_view&, bool, diagnostics&) override final;
BOOST_MYSQL_DECL
error_code on_row_impl(span<const std::uint8_t> msg, const output_ref&, std::vector<field_view>&)
override final;
BOOST_MYSQL_DECL
error_code on_row_ok_packet_impl(const ok_view& pack) override final;
BOOST_MYSQL_DECL
void on_row_batch_start_impl() override final;
BOOST_MYSQL_DECL
void on_row_batch_finish_impl() override final;
// Data
std::vector<metadata> meta_;
resultset_container per_result_;
std::vector<char> info_;
row_impl rows_;
std::size_t num_fields_at_batch_start_{no_batch};
// Auxiliar
static constexpr std::size_t no_batch = std::size_t(-1);
bool has_active_batch() const noexcept { return num_fields_at_batch_start_ != no_batch; }
BOOST_MYSQL_DECL
void finish_batch();
per_resultset_data& current_resultset() noexcept
{
BOOST_ASSERT(!per_result_.empty());
return per_result_.back();
}
const per_resultset_data& current_resultset() const noexcept
{
BOOST_ASSERT(!per_result_.empty());
return per_result_.back();
}
BOOST_MYSQL_DECL
per_resultset_data& add_resultset();
BOOST_MYSQL_DECL
void on_ok_packet_impl(const ok_view& pack);
const per_resultset_data& get_resultset(std::size_t index) const noexcept
{
BOOST_ASSERT(index < per_result_.size());
return per_result_[index];
}
metadata_collection_view current_resultset_meta() const noexcept
{
return get_meta(per_result_.size() - 1);
}
};
} // namespace detail
} // namespace mysql
} // namespace boost
#ifdef BOOST_MYSQL_HEADER_ONLY
#include <boost/mysql/impl/results_impl.ipp>
#endif
#endif
@@ -0,0 +1,295 @@
//
// Copyright (c) 2019-2023 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_DETAIL_EXECUTION_PROCESSOR_STATIC_EXECUTION_STATE_IMPL_HPP
#define BOOST_MYSQL_DETAIL_EXECUTION_PROCESSOR_STATIC_EXECUTION_STATE_IMPL_HPP
#include <boost/mysql/detail/config.hpp>
#ifdef BOOST_MYSQL_CXX14
#include <boost/mysql/diagnostics.hpp>
#include <boost/mysql/error_code.hpp>
#include <boost/mysql/field_view.hpp>
#include <boost/mysql/metadata.hpp>
#include <boost/mysql/metadata_collection_view.hpp>
#include <boost/mysql/string_view.hpp>
#include <boost/mysql/detail/execution_processor/execution_processor.hpp>
#include <boost/mysql/detail/typing/get_type_index.hpp>
#include <boost/mysql/detail/typing/row_traits.hpp>
#include <boost/assert.hpp>
#include <array>
#include <cstddef>
#include <vector>
namespace boost {
namespace mysql {
namespace detail {
using execst_parse_fn_t =
error_code (*)(span<const std::size_t> pos_map, span<const field_view> from, const output_ref& ref);
struct execst_resultset_descriptor
{
std::size_t num_columns;
name_table_t name_table;
meta_check_fn_t meta_check;
execst_parse_fn_t parse_fn;
std::size_t type_index;
};
class execst_external_data
{
public:
struct ptr_data
{
std::size_t* pos_map;
};
execst_external_data(span<const execst_resultset_descriptor> desc, ptr_data ptr) noexcept
: desc_(desc), ptr_(ptr)
{
}
std::size_t num_resultsets() const noexcept { return desc_.size(); }
std::size_t num_columns(std::size_t idx) const noexcept
{
BOOST_ASSERT(idx < num_resultsets());
return desc_[idx].num_columns;
}
name_table_t name_table(std::size_t idx) const noexcept
{
BOOST_ASSERT(idx < num_resultsets());
return desc_[idx].name_table;
}
meta_check_fn_t meta_check_fn(std::size_t idx) const noexcept
{
BOOST_ASSERT(idx < num_resultsets());
return desc_[idx].meta_check;
}
execst_parse_fn_t parse_fn(std::size_t idx) const noexcept
{
BOOST_ASSERT(idx < num_resultsets());
return desc_[idx].parse_fn;
}
std::size_t type_index(std::size_t idx) const noexcept
{
BOOST_ASSERT(idx < num_resultsets());
return desc_[idx].type_index;
}
span<std::size_t> pos_map(std::size_t idx) const noexcept
{
return span<std::size_t>(ptr_.pos_map, num_columns(idx));
}
void set_pointers(ptr_data ptr) noexcept { ptr_ = ptr; }
private:
span<const execst_resultset_descriptor> desc_;
ptr_data ptr_;
};
class static_execution_state_erased_impl final : public execution_processor
{
public:
static_execution_state_erased_impl(execst_external_data ext) noexcept : ext_(ext) {}
execst_external_data& ext_data() noexcept { return ext_; }
metadata_collection_view meta() const noexcept { return meta_; }
std::uint64_t get_affected_rows() const noexcept
{
BOOST_ASSERT(ok_data_.has_value);
return ok_data_.affected_rows;
}
std::uint64_t get_last_insert_id() const noexcept
{
BOOST_ASSERT(ok_data_.has_value);
return ok_data_.last_insert_id;
}
unsigned get_warning_count() const noexcept
{
BOOST_ASSERT(ok_data_.has_value);
return ok_data_.warnings;
}
string_view get_info() const noexcept
{
BOOST_ASSERT(ok_data_.has_value);
return string_view(info_.data(), info_.size());
}
bool get_is_out_params() const noexcept
{
BOOST_ASSERT(ok_data_.has_value);
return ok_data_.is_out_params;
}
private:
// Data
struct ok_packet_data
{
bool has_value{false}; // The OK packet information is default constructed, or actual data?
std::uint64_t affected_rows{}; // OK packet data
std::uint64_t last_insert_id{}; // OK packet data
std::uint16_t warnings{}; // OK packet data
bool is_out_params{false}; // Does this resultset contain OUT param information?
};
execst_external_data ext_;
std::size_t resultset_index_{};
ok_packet_data ok_data_;
std::vector<char> info_;
std::vector<metadata> meta_;
// Virtual impls
BOOST_MYSQL_DECL
void reset_impl() noexcept override final;
BOOST_MYSQL_DECL
error_code on_head_ok_packet_impl(const ok_view& pack, diagnostics& diag) override final;
BOOST_MYSQL_DECL
void on_num_meta_impl(std::size_t num_columns) override final;
BOOST_MYSQL_DECL
error_code on_meta_impl(const coldef_view& coldef, bool is_last, diagnostics& diag) override final;
BOOST_MYSQL_DECL
error_code on_row_impl(
span<const std::uint8_t> msg,
const output_ref& ref,
std::vector<field_view>& fields
) override final;
BOOST_MYSQL_DECL
error_code on_row_ok_packet_impl(const ok_view& pack) override final;
void on_row_batch_start_impl() noexcept override final {}
void on_row_batch_finish_impl() noexcept override final {}
// Auxiliar
name_table_t current_name_table() const noexcept { return ext_.name_table(resultset_index_ - 1); }
span<std::size_t> current_pos_map() noexcept { return ext_.pos_map(resultset_index_ - 1); }
span<const std::size_t> current_pos_map() const noexcept { return ext_.pos_map(resultset_index_ - 1); }
error_code meta_check(diagnostics& diag) const
{
return ext_.meta_check_fn(resultset_index_ - 1)(current_pos_map(), meta_, diag);
}
BOOST_MYSQL_DECL
void on_new_resultset() noexcept;
BOOST_MYSQL_DECL
error_code on_ok_packet_impl(const ok_view& pack);
};
template <class StaticRow>
static error_code execst_parse_fn(
span<const std::size_t> pos_map,
span<const field_view> from,
const output_ref& ref
)
{
return parse(pos_map, from, ref.span_element<StaticRow>());
}
template <class... StaticRow>
constexpr std::array<execst_resultset_descriptor, sizeof...(StaticRow)> create_execst_resultset_descriptors()
{
return {{{
get_row_size<StaticRow>(),
get_row_name_table<StaticRow>(),
&meta_check<StaticRow>,
&execst_parse_fn<StaticRow>,
get_type_index<StaticRow, StaticRow...>(),
}...}};
}
template <class... StaticRow>
constexpr std::array<execst_resultset_descriptor, sizeof...(StaticRow)>
execst_resultset_descriptor_table = create_execst_resultset_descriptors<StaticRow...>();
template <BOOST_MYSQL_STATIC_ROW... StaticRow>
class static_execution_state_impl
{
// Storage for our data, which requires knowing the template args
struct
{
std::array<std::size_t, max_num_columns<StaticRow...>> pos_map{};
} data_;
// The type-erased impl, that will use pointers to the above storage
static_execution_state_erased_impl impl_;
execst_external_data::ptr_data ptr_data() noexcept
{
return {
data_.pos_map.data(),
};
}
void set_pointers() noexcept { impl_.ext_data().set_pointers(ptr_data()); }
public:
static_execution_state_impl() noexcept
: impl_({execst_resultset_descriptor_table<StaticRow...>, ptr_data()})
{
}
static_execution_state_impl(const static_execution_state_impl& rhs) : data_(rhs.data_), impl_(rhs.impl_)
{
set_pointers();
}
static_execution_state_impl(static_execution_state_impl&& rhs) noexcept
: data_(std::move(rhs.data_)), impl_(std::move(rhs.impl_))
{
set_pointers();
}
static_execution_state_impl& operator=(const static_execution_state_impl& rhs)
{
data_ = rhs.data_;
impl_ = rhs.impl_;
set_pointers();
return *this;
}
static_execution_state_impl& operator=(static_execution_state_impl&& rhs)
{
data_ = std::move(rhs.data_);
impl_ = std::move(rhs.impl_);
set_pointers();
return *this;
}
~static_execution_state_impl() = default;
const static_execution_state_erased_impl& get_interface() const noexcept { return impl_; }
static_execution_state_erased_impl& get_interface() noexcept { return impl_; }
};
} // namespace detail
} // namespace mysql
} // namespace boost
#ifdef BOOST_MYSQL_HEADER_ONLY
#include <boost/mysql/impl/static_execution_state_impl.ipp>
#endif
#endif // BOOST_MYSQL_CXX14
#endif
@@ -0,0 +1,349 @@
//
// Copyright (c) 2019-2023 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_DETAIL_EXECUTION_PROCESSOR_STATIC_RESULTS_IMPL_HPP
#define BOOST_MYSQL_DETAIL_EXECUTION_PROCESSOR_STATIC_RESULTS_IMPL_HPP
#include <boost/mysql/detail/config.hpp>
#ifdef BOOST_MYSQL_CXX14
#include <boost/mysql/diagnostics.hpp>
#include <boost/mysql/field_view.hpp>
#include <boost/mysql/metadata.hpp>
#include <boost/mysql/metadata_collection_view.hpp>
#include <boost/mysql/string_view.hpp>
#include <boost/mysql/detail/execution_processor/execution_processor.hpp>
#include <boost/mysql/detail/typing/readable_field_traits.hpp>
#include <boost/mysql/detail/typing/row_traits.hpp>
#include <boost/assert.hpp>
#include <boost/mp11/algorithm.hpp>
#include <boost/mp11/integer_sequence.hpp>
#include <array>
#include <cstddef>
namespace boost {
namespace mysql {
namespace detail {
using results_reset_fn_t = void (*)(void*);
using results_parse_fn_t =
error_code (*)(span<const std::size_t> pos_map, span<const field_view> from, void* to);
struct results_resultset_descriptor
{
std::size_t num_columns;
name_table_t name_table;
meta_check_fn_t meta_check;
results_parse_fn_t parse_fn;
};
struct static_per_resultset_data
{
std::size_t meta_offset{};
std::size_t meta_size{};
std::size_t info_offset{};
std::size_t info_size{};
bool has_ok_packet_data{false}; // The OK packet information is default constructed, or actual data?
std::uint64_t affected_rows{}; // OK packet data
std::uint64_t last_insert_id{}; // OK packet data
std::uint16_t warnings{}; // OK packet data
bool is_out_params{false}; // Does this resultset contain OUT param information?
};
class results_external_data
{
public:
struct ptr_data
{
void* rows;
std::size_t* pos_map;
static_per_resultset_data* per_resultset;
};
results_external_data(
span<const results_resultset_descriptor> desc,
results_reset_fn_t reset,
ptr_data ptr
) noexcept
: desc_(desc), reset_(reset), ptr_(ptr)
{
}
void set_pointers(ptr_data ptr) noexcept { ptr_ = ptr; }
std::size_t num_resultsets() const noexcept { return desc_.size(); }
std::size_t num_columns(std::size_t idx) const noexcept
{
BOOST_ASSERT(idx < num_resultsets());
return desc_[idx].num_columns;
}
name_table_t name_table(std::size_t idx) const noexcept
{
BOOST_ASSERT(idx < num_resultsets());
return desc_[idx].name_table;
}
meta_check_fn_t meta_check_fn(std::size_t idx) const noexcept
{
BOOST_ASSERT(idx < num_resultsets());
return desc_[idx].meta_check;
}
results_parse_fn_t parse_fn(std::size_t idx) const noexcept
{
BOOST_ASSERT(idx < num_resultsets());
return desc_[idx].parse_fn;
}
results_reset_fn_t reset_fn() const noexcept { return reset_; }
void* rows() const noexcept { return ptr_.rows; }
span<std::size_t> pos_map(std::size_t idx) const noexcept
{
return span<std::size_t>(ptr_.pos_map, num_columns(idx));
}
static_per_resultset_data& per_result(std::size_t idx) const noexcept
{
BOOST_ASSERT(idx < num_resultsets());
return ptr_.per_resultset[idx];
}
private:
span<const results_resultset_descriptor> desc_;
results_reset_fn_t reset_;
ptr_data ptr_;
};
class static_results_erased_impl final : public execution_processor
{
public:
static_results_erased_impl(results_external_data ext) noexcept : ext_(ext) {}
results_external_data& ext_data() noexcept { return ext_; }
metadata_collection_view get_meta(std::size_t index) const noexcept
{
const auto& resultset_data = ext_.per_result(index);
return metadata_collection_view(meta_.data() + resultset_data.meta_offset, resultset_data.meta_size);
}
std::uint64_t get_affected_rows(std::size_t index) const noexcept
{
return ext_.per_result(index).affected_rows;
}
std::uint64_t get_last_insert_id(std::size_t index) const noexcept
{
return ext_.per_result(index).last_insert_id;
}
unsigned get_warning_count(std::size_t index) const noexcept { return ext_.per_result(index).warnings; }
string_view get_info(std::size_t index) const noexcept
{
const auto& resultset_data = ext_.per_result(index);
return string_view(info_.data() + resultset_data.info_offset, resultset_data.info_size);
}
bool get_is_out_params(std::size_t index) const noexcept { return ext_.per_result(index).is_out_params; }
private:
// Virtual implementations
BOOST_MYSQL_DECL
void reset_impl() noexcept override final;
BOOST_MYSQL_DECL
error_code on_head_ok_packet_impl(const ok_view& pack, diagnostics& diag) override final;
BOOST_MYSQL_DECL
void on_num_meta_impl(std::size_t num_columns) override final;
BOOST_MYSQL_DECL
error_code on_meta_impl(const coldef_view& coldef, bool is_last, diagnostics& diag) override final;
BOOST_MYSQL_DECL
error_code on_row_impl(span<const std::uint8_t> msg, const output_ref&, std::vector<field_view>& fields)
override final;
BOOST_MYSQL_DECL
error_code on_row_ok_packet_impl(const ok_view& pack) override final;
void on_row_batch_start_impl() override final {}
void on_row_batch_finish_impl() override final {}
// Data
results_external_data ext_;
std::vector<metadata> meta_;
std::vector<char> info_;
std::size_t resultset_index_{0};
// Helpers
span<std::size_t> current_pos_map() noexcept { return ext_.pos_map(resultset_index_ - 1); }
span<const std::size_t> current_pos_map() const noexcept { return ext_.pos_map(resultset_index_ - 1); }
name_table_t current_name_table() const noexcept { return ext_.name_table(resultset_index_ - 1); }
static_per_resultset_data& current_resultset() noexcept { return ext_.per_result(resultset_index_ - 1); }
metadata_collection_view current_resultset_meta() const noexcept
{
return get_meta(resultset_index_ - 1);
}
BOOST_MYSQL_DECL
static_per_resultset_data& add_resultset();
BOOST_MYSQL_DECL
error_code on_ok_packet_impl(const ok_view& pack);
error_code meta_check(diagnostics& diag) const
{
return ext_.meta_check_fn(resultset_index_ - 1)(current_pos_map(), current_resultset_meta(), diag);
}
};
template <class... StaticRow>
using results_rows_t = std::tuple<std::vector<StaticRow>...>;
template <class... StaticRow>
struct results_fns
{
using rows_t = results_rows_t<StaticRow...>;
struct reset_fn
{
rows_t& obj;
template <std::size_t I>
void operator()(boost::mp11::mp_size_t<I>) const noexcept
{
std::get<I>(obj).clear();
}
};
static void reset(void* rows_ptr) noexcept
{
auto& rows = *static_cast<rows_t*>(rows_ptr);
boost::mp11::mp_for_each<boost::mp11::mp_iota_c<sizeof...(StaticRow)>>(reset_fn{rows});
}
template <std::size_t I>
static error_code do_parse(span<const std::size_t> pos_map, span<const field_view> from, void* to)
{
auto& v = std::get<I>(*static_cast<rows_t*>(to));
v.emplace_back();
return parse(pos_map, from, v.back());
}
template <std::size_t I>
static constexpr results_resultset_descriptor create_descriptor()
{
using T = mp11::mp_at_c<mp11::mp_list<StaticRow...>, I>;
return {
get_row_size<T>(),
get_row_name_table<T>(),
&meta_check<T>,
&do_parse<I>,
};
}
template <std::size_t... I>
static constexpr std::array<results_resultset_descriptor, sizeof...(StaticRow)> create_descriptors(mp11::index_sequence<
I...>)
{
return {{create_descriptor<I>()...}};
}
};
template <class... StaticRow>
constexpr std::array<results_resultset_descriptor, sizeof...(StaticRow)>
results_resultset_descriptor_table = results_fns<StaticRow...>::create_descriptors(
mp11::make_index_sequence<sizeof...(StaticRow)>()
);
template <BOOST_MYSQL_STATIC_ROW... StaticRow>
class static_results_impl
{
// Data that requires knowing template params
struct
{
results_rows_t<StaticRow...> rows;
std::array<std::size_t, max_num_columns<StaticRow...>> pos_map{};
std::array<static_per_resultset_data, sizeof...(StaticRow)> per_resultset{};
} data_;
// The type-erased impl, that will use pointers to the above storage
static_results_erased_impl impl_;
results_external_data::ptr_data ptr_data() noexcept
{
return {
&data_.rows,
data_.pos_map.data(),
data_.per_resultset.data(),
};
}
void set_pointers() noexcept { impl_.ext_data().set_pointers(ptr_data()); }
public:
static_results_impl() noexcept
: impl_(results_external_data(
results_resultset_descriptor_table<StaticRow...>,
&results_fns<StaticRow...>::reset,
ptr_data()
))
{
}
static_results_impl(const static_results_impl& rhs) : data_(rhs.data_), impl_(rhs.impl_)
{
set_pointers();
}
static_results_impl(static_results_impl&& rhs) noexcept
: data_(std::move(rhs.data_)), impl_(std::move(rhs.impl_))
{
set_pointers();
}
static_results_impl& operator=(const static_results_impl& rhs)
{
data_ = rhs.data_;
impl_ = rhs.impl_;
set_pointers();
return *this;
}
static_results_impl& operator=(static_results_impl&& rhs)
{
data_ = std::move(rhs.data_);
impl_ = std::move(rhs.impl_);
set_pointers();
return *this;
}
// User facing
template <std::size_t I>
boost::span<const typename std::tuple_element<I, std::tuple<StaticRow...>>::type> get_rows(
) const noexcept
{
return std::get<I>(data_.rows);
}
const static_results_erased_impl& get_interface() const noexcept { return impl_; }
static_results_erased_impl& get_interface() noexcept { return impl_; }
};
} // namespace detail
} // namespace mysql
} // namespace boost
#ifdef BOOST_MYSQL_HEADER_ONLY
#include <boost/mysql/impl/static_results_impl.ipp>
#endif
#endif // BOOST_MYSQL_CXX14
#endif