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
+44
View File
@@ -0,0 +1,44 @@
//
// 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_ACCESS_HPP
#define BOOST_MYSQL_DETAIL_ACCESS_HPP
#include <utility>
namespace boost {
namespace mysql {
namespace detail {
// Exposes access to the implementation of public access, which is sometimes
// required by library internals.
struct access
{
template <class T>
static decltype(std::declval<T>().impl_)& get_impl(T& obj) noexcept
{
return obj.impl_;
}
template <class T>
static const decltype(std::declval<T>().impl_)& get_impl(const T& obj) noexcept
{
return obj.impl_;
}
template <class T, class... Args>
static T construct(Args&&... args)
{
return T(std::forward<Args>(args)...);
}
};
} // namespace detail
} // namespace mysql
} // namespace boost
#endif
+48
View File
@@ -0,0 +1,48 @@
//
// 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_ANY_EXECUTION_REQUEST_HPP
#define BOOST_MYSQL_DETAIL_ANY_EXECUTION_REQUEST_HPP
#include <boost/mysql/field_view.hpp>
#include <boost/mysql/statement.hpp>
#include <boost/mysql/string_view.hpp>
#include <boost/core/span.hpp>
namespace boost {
namespace mysql {
namespace detail {
struct any_execution_request
{
union data_t
{
string_view query;
struct
{
statement stmt;
span<const field_view> params;
} stmt;
data_t(string_view q) noexcept : query(q) {}
data_t(statement s, span<const field_view> params) noexcept : stmt{s, params} {}
} data;
bool is_query;
any_execution_request(string_view q) noexcept : data(q), is_query(true) {}
any_execution_request(statement s, span<const field_view> params) noexcept
: data(s, params), is_query(false)
{
}
};
} // namespace detail
} // namespace mysql
} // namespace boost
#endif
+82
View File
@@ -0,0 +1,82 @@
//
// 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_ANY_STREAM_HPP
#define BOOST_MYSQL_DETAIL_ANY_STREAM_HPP
#include <boost/mysql/error_code.hpp>
#include <boost/asio/any_completion_handler.hpp>
#include <boost/asio/any_io_executor.hpp>
#include <boost/asio/buffer.hpp>
#include <cstddef>
namespace boost {
namespace mysql {
namespace detail {
class any_stream
{
public:
any_stream(bool supports_ssl) noexcept
: ssl_state_(supports_ssl ? ssl_state::inactive : ssl_state::unsupported)
{
}
bool ssl_active() const noexcept { return ssl_state_ == ssl_state::active; }
void reset_ssl_active() noexcept
{
if (ssl_state_ == ssl_state::active)
ssl_state_ = ssl_state::inactive;
}
void set_ssl_active() noexcept
{
BOOST_ASSERT(ssl_state_ != ssl_state::unsupported);
ssl_state_ = ssl_state::active;
}
bool supports_ssl() const noexcept { return ssl_state_ != ssl_state::unsupported; }
using executor_type = asio::any_io_executor;
virtual ~any_stream() {}
virtual executor_type get_executor() = 0;
// SSL
virtual void handshake(error_code& ec) = 0;
virtual void async_handshake(asio::any_completion_handler<void(error_code)>) = 0;
virtual void shutdown(error_code& ec) = 0;
virtual void async_shutdown(asio::any_completion_handler<void(error_code)>) = 0;
// Reading
virtual std::size_t read_some(asio::mutable_buffer, error_code& ec) = 0;
virtual void async_read_some(asio::mutable_buffer, asio::any_completion_handler<void(error_code, std::size_t)>) = 0;
// Writing
virtual std::size_t write_some(asio::const_buffer, error_code& ec) = 0;
virtual void async_write_some(asio::const_buffer, asio::any_completion_handler<void(error_code, std::size_t)>) = 0;
// Connect and close - these apply only to SocketStream's
virtual void connect(const void* endpoint, error_code& ec) = 0;
virtual void async_connect(const void* endpoint, asio::any_completion_handler<void(error_code)>) = 0;
virtual void close(error_code& ec) = 0;
virtual bool is_open() const noexcept = 0;
private:
enum class ssl_state
{
inactive,
active,
unsupported
} ssl_state_;
};
} // namespace detail
} // namespace mysql
} // namespace boost
#endif
+307
View File
@@ -0,0 +1,307 @@
//
// 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_ANY_STREAM_IMPL_HPP
#define BOOST_MYSQL_DETAIL_ANY_STREAM_IMPL_HPP
#include <boost/mysql/error_code.hpp>
#include <boost/mysql/detail/any_stream.hpp>
#include <boost/mysql/detail/config.hpp>
#include <boost/mysql/detail/socket_stream.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/ssl/stream.hpp>
#include <boost/config.hpp>
#include <type_traits>
namespace boost {
namespace mysql {
namespace detail {
// Connect and close helpers
template <class Stream>
const typename Stream::lowest_layer_type::endpoint_type cast_endpoint(const void* input) noexcept
{
return *static_cast<const typename Stream::lowest_layer_type::endpoint_type*>(input);
}
template <class Stream>
void do_connect_impl(Stream&, const void*, error_code&, std::false_type)
{
BOOST_ASSERT(false);
}
template <class Stream>
void do_connect_impl(Stream& stream, const void* endpoint, error_code& ec, std::true_type)
{
stream.lowest_layer().connect(cast_endpoint<Stream>(endpoint), ec);
}
template <class Stream>
void do_connect(Stream& stream, const void* endpoint, error_code& ec)
{
do_connect_impl(stream, endpoint, ec, is_socket_stream<Stream>{});
}
template <class Stream>
void do_async_connect_impl(
Stream&,
const void*,
asio::any_completion_handler<void(error_code)>&&,
std::false_type
)
{
BOOST_ASSERT(false);
}
template <class Stream>
void do_async_connect_impl(
Stream& stream,
const void* endpoint,
asio::any_completion_handler<void(error_code)>&& handler,
std::true_type
)
{
stream.lowest_layer().async_connect(cast_endpoint<Stream>(endpoint), std::move(handler));
}
template <class Stream>
void do_async_connect(
Stream& stream,
const void* endpoint,
asio::any_completion_handler<void(error_code)>&& handler
)
{
do_async_connect_impl(stream, endpoint, std::move(handler), is_socket_stream<Stream>{});
}
template <class Stream>
void do_close_impl(Stream&, error_code&, std::false_type)
{
BOOST_ASSERT(false);
}
template <class Stream>
void do_close_impl(Stream& stream, error_code& ec, std::true_type)
{
stream.lowest_layer().shutdown(asio::socket_base::shutdown_both, ec);
stream.lowest_layer().close(ec);
}
template <class Stream>
void do_close(Stream& stream, error_code& ec)
{
do_close_impl(stream, ec, is_socket_stream<Stream>{});
}
template <class Stream>
bool do_is_open_impl(const Stream&, std::false_type) noexcept
{
return false;
}
template <class Stream>
bool do_is_open_impl(const Stream& stream, std::true_type) noexcept
{
return stream.lowest_layer().is_open();
}
template <class Stream>
bool do_is_open(const Stream& stream) noexcept
{
return do_is_open_impl(stream, is_socket_stream<Stream>{});
}
template <class Stream>
class any_stream_impl final : public any_stream
{
Stream stream_;
public:
template <class... Args>
any_stream_impl(Args&&... args) : any_stream(false), stream_(std::forward<Args>(args)...)
{
}
Stream& stream() noexcept { return stream_; }
const Stream& stream() const noexcept { return stream_; }
executor_type get_executor() override final { return stream_.get_executor(); }
// SSL
void handshake(error_code&) final override { BOOST_ASSERT(false); }
void async_handshake(asio::any_completion_handler<void(error_code)>) final override
{
BOOST_ASSERT(false);
}
void shutdown(error_code&) final override { BOOST_ASSERT(false); }
void async_shutdown(asio::any_completion_handler<void(error_code)>) final override
{
BOOST_ASSERT(false);
}
// Reading
std::size_t read_some(boost::asio::mutable_buffer buff, error_code& ec) final override
{
return stream_.read_some(buff, ec);
}
void async_read_some(
boost::asio::mutable_buffer buff,
asio::any_completion_handler<void(error_code, std::size_t)> handler
) final override
{
return stream_.async_read_some(buff, std::move(handler));
}
// Writing
std::size_t write_some(boost::asio::const_buffer buff, error_code& ec) final override
{
return stream_.write_some(buff, ec);
}
void async_write_some(
boost::asio::const_buffer buff,
asio::any_completion_handler<void(error_code, std::size_t)> handler
) final override
{
return stream_.async_write_some(buff, std::move(handler));
}
// Connect and close
void connect(const void* endpoint, error_code& ec) override final { do_connect(stream_, endpoint, ec); }
void async_connect(const void* endpoint, asio::any_completion_handler<void(error_code)> handler)
override final
{
do_async_connect(stream_, endpoint, std::move(handler));
}
void close(error_code& ec) override final { do_close(stream_, ec); }
bool is_open() const noexcept override { return do_is_open(stream_); }
};
template <class Stream>
class any_stream_impl<asio::ssl::stream<Stream>> final : public any_stream
{
asio::ssl::stream<Stream> stream_;
public:
template <class... Args>
any_stream_impl(Args&&... args) : any_stream(true), stream_(std::forward<Args>(args)...)
{
}
asio::ssl::stream<Stream>& stream() noexcept { return stream_; }
const asio::ssl::stream<Stream>& stream() const noexcept { return stream_; }
executor_type get_executor() override final { return stream_.get_executor(); }
// SSL
void handshake(error_code& ec) override final
{
set_ssl_active();
stream_.handshake(boost::asio::ssl::stream_base::client, ec);
}
void async_handshake(asio::any_completion_handler<void(error_code)> handler) override final
{
set_ssl_active();
stream_.async_handshake(boost::asio::ssl::stream_base::client, std::move(handler));
}
void shutdown(error_code& ec) override final { stream_.shutdown(ec); }
void async_shutdown(asio::any_completion_handler<void(error_code)> handler) override final
{
return stream_.async_shutdown(std::move(handler));
}
// Reading
std::size_t read_some(boost::asio::mutable_buffer buff, error_code& ec) override final
{
if (ssl_active())
{
return stream_.read_some(buff, ec);
}
else
{
return stream_.next_layer().read_some(buff, ec);
}
}
void async_read_some(
boost::asio::mutable_buffer buff,
asio::any_completion_handler<void(error_code, std::size_t)> handler
) override final
{
if (ssl_active())
{
return stream_.async_read_some(buff, std::move(handler));
}
else
{
return stream_.next_layer().async_read_some(buff, std::move(handler));
}
}
// Writing
std::size_t write_some(boost::asio::const_buffer buff, error_code& ec) override final
{
if (ssl_active())
{
return stream_.write_some(buff, ec);
}
else
{
return stream_.next_layer().write_some(buff, ec);
}
}
void async_write_some(
boost::asio::const_buffer buff,
asio::any_completion_handler<void(error_code, std::size_t)> handler
) override final
{
if (ssl_active())
{
stream_.async_write_some(buff, std::move(handler));
}
else
{
return stream_.next_layer().async_write_some(buff, std::move(handler));
}
}
// Connect and close
void connect(const void* endpoint, error_code& ec) override final { do_connect(stream_, endpoint, ec); }
void async_connect(const void* endpoint, asio::any_completion_handler<void(error_code)> handler)
override final
{
do_async_connect(stream_, endpoint, std::move(handler));
}
void close(error_code& ec) override final { do_close(stream_, ec); }
bool is_open() const noexcept override { return do_is_open(stream_); }
};
template <class Stream>
const Stream& cast(const any_stream& obj) noexcept
{
return static_cast<const any_stream_impl<Stream>&>(obj).stream();
}
template <class Stream>
Stream& cast(any_stream& obj) noexcept
{
return static_cast<any_stream_impl<Stream>&>(obj).stream();
}
#ifdef BOOST_MYSQL_SEPARATE_COMPILATION
extern template class any_stream_impl<asio::ssl::stream<asio::ip::tcp::socket>>;
extern template class any_stream_impl<asio::ip::tcp::socket>;
#endif
} // namespace detail
} // namespace mysql
} // namespace boost
// any_stream_impl.ipp explicitly instantiates any_stream_impl, so not included here
#endif
+71
View File
@@ -0,0 +1,71 @@
//
// 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_CHANNEL_PTR_HPP
#define BOOST_MYSQL_DETAIL_CHANNEL_PTR_HPP
#include <boost/mysql/diagnostics.hpp>
#include <boost/mysql/field_view.hpp>
#include <boost/mysql/metadata_mode.hpp>
#include <boost/mysql/detail/any_stream.hpp>
#include <boost/mysql/detail/config.hpp>
#include <boost/assert.hpp>
#include <memory>
namespace boost {
namespace mysql {
namespace detail {
class channel;
class channel_ptr
{
std::unique_ptr<channel> chan_;
BOOST_MYSQL_DECL any_stream& get_stream() const;
public:
BOOST_MYSQL_DECL channel_ptr(std::size_t read_buff_size, std::unique_ptr<any_stream>);
channel_ptr(const channel_ptr&) = delete;
BOOST_MYSQL_DECL channel_ptr(channel_ptr&&) noexcept;
channel_ptr& operator=(const channel_ptr&) = delete;
BOOST_MYSQL_DECL channel_ptr& operator=(channel_ptr&&) noexcept;
BOOST_MYSQL_DECL ~channel_ptr();
any_stream& stream() noexcept { return get_stream(); }
const any_stream& stream() const noexcept { return get_stream(); }
channel& get() noexcept
{
BOOST_ASSERT(chan_);
return *chan_;
}
const channel& get() const noexcept
{
BOOST_ASSERT(chan_);
return *chan_;
}
BOOST_MYSQL_DECL metadata_mode meta_mode() const noexcept;
BOOST_MYSQL_DECL void set_meta_mode(metadata_mode v) noexcept;
BOOST_MYSQL_DECL diagnostics& shared_diag() noexcept;
};
BOOST_MYSQL_DECL std::vector<field_view>& get_shared_fields(channel&) noexcept;
} // namespace detail
} // namespace mysql
} // namespace boost
#ifdef BOOST_MYSQL_HEADER_ONLY
#include <boost/mysql/impl/channel_ptr.ipp>
#endif
#endif
+37
View File
@@ -0,0 +1,37 @@
//
// 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_COLDEF_VIEW_HPP
#define BOOST_MYSQL_DETAIL_COLDEF_VIEW_HPP
#include <boost/mysql/column_type.hpp>
#include <boost/mysql/string_view.hpp>
namespace boost {
namespace mysql {
namespace detail {
struct coldef_view
{
string_view database;
string_view table;
string_view org_table;
string_view name;
string_view org_name;
std::uint16_t collation_id;
std::uint32_t column_length; // maximum length of the field
column_type type;
std::uint16_t flags;
std::uint8_t decimals; // max shown decimal digits. 0x00 for int/static strings; 0x1f for
// dynamic strings, double, float
};
} // namespace detail
} // namespace mysql
} // namespace boost
#endif
+44
View File
@@ -0,0 +1,44 @@
//
// 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_CONFIG_HPP
#define BOOST_MYSQL_DETAIL_CONFIG_HPP
#include <boost/config.hpp>
// clang-format off
// Concepts
#if defined(__has_include)
#if __has_include(<version>)
#include <version>
#if defined(__cpp_concepts) && defined(__cpp_lib_concepts)
#define BOOST_MYSQL_HAS_CONCEPTS
#endif
#endif
#endif
// C++14 conformance
#if BOOST_CXX_VERSION >= 201402L
#define BOOST_MYSQL_CXX14
#endif
// Separate build
#if defined(BOOST_MYSQL_SEPARATE_COMPILATION)
#define BOOST_MYSQL_DECL
#define BOOST_MYSQL_STATIC_IF_COMPILED static
#define BOOST_MYSQL_STATIC_OR_INLINE static
#else
#define BOOST_MYSQL_HEADER_ONLY
#define BOOST_MYSQL_DECL inline
#define BOOST_MYSQL_STATIC_IF_COMPILED
#define BOOST_MYSQL_STATIC_OR_INLINE inline
#endif
// clang-format on
#endif
+104
View File
@@ -0,0 +1,104 @@
//
// 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_DATETIME_HPP
#define BOOST_MYSQL_DETAIL_DATETIME_HPP
// All these algorithms have been taken from:
// http://howardhinnant.github.io/date_algorithms.html
#include <boost/assert.hpp>
#include <boost/config.hpp>
#include <cstdint>
#include <limits>
namespace boost {
namespace mysql {
namespace detail {
// Helpers
constexpr unsigned char last_month_day_arr[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
constexpr bool is_leap(std::uint16_t y) noexcept { return y % 4 == 0 && (y % 100 != 0 || y % 400 == 0); }
constexpr inline std::uint8_t last_month_day(std::uint16_t y, std::uint8_t m) noexcept
{
return m != 2 || !is_leap(y) ? last_month_day_arr[m - 1] : 29u;
}
// Interface
constexpr std::uint16_t max_year = 9999;
constexpr std::uint8_t max_month = 12;
constexpr std::uint8_t max_day = 31;
constexpr std::uint8_t max_hour = 23;
constexpr std::uint8_t max_min = 59;
constexpr std::uint8_t max_sec = 59;
constexpr std::uint32_t max_micro = 999999;
constexpr inline bool is_valid(std::uint16_t years, std::uint8_t month, std::uint8_t day) noexcept
{
return years <= max_year && month > 0 && month <= max_month && day > 0 &&
day <= last_month_day(years, month);
}
BOOST_CXX14_CONSTEXPR inline int ymd_to_days(
std::uint16_t years,
std::uint8_t month,
std::uint8_t day
) noexcept
{
BOOST_ASSERT(is_valid(years, month, day));
int y = years;
const int m = month;
const int d = day;
y -= m <= 2;
const int era = (y >= 0 ? y : y - 399) / 400;
const unsigned yoe = static_cast<unsigned>(y - era * 400); // [0, 399]
const unsigned doy = (153 * (m + (m > 2 ? -3 : 9)) + 2) / 5 + d - 1; // [0, 365]
const unsigned doe = yoe * 365 + yoe / 4 - yoe / 100 + doy; // [0, 146096]
return era * 146097 + static_cast<int>(doe) - 719468;
}
BOOST_CXX14_CONSTEXPR inline bool days_to_ymd(
int num_days,
std::uint16_t& years,
std::uint8_t& month,
std::uint8_t& day
) noexcept
{
// Prevent overflow
constexpr int days_magic = 719468;
if (num_days > (std::numeric_limits<int>::max)() - days_magic)
return false;
num_days += days_magic;
const int era = (num_days >= 0 ? num_days : num_days - 146096) / 146097;
const unsigned doe = static_cast<unsigned>(num_days - era * 146097); // [0, 146096]
const unsigned yoe = (doe - doe / 1460 + doe / 36524 - doe / 146096) / 365; // [0, 399]
const int y = static_cast<int>(yoe) + era * 400;
const unsigned doy = doe - (365 * yoe + yoe / 4 - yoe / 100); // [0, 365]
const unsigned mp = (5 * doy + 2) / 153; // [0, 11]
const unsigned d = doy - (153 * mp + 2) / 5 + 1; // [1, 31]
const unsigned m = mp + (mp < 10 ? 3 : -9); // [1, 12]
const int final_year = y + (m <= 2);
if (final_year < 0 || final_year > static_cast<int>(max_year))
return false;
else
{
years = static_cast<std::uint16_t>(final_year);
month = static_cast<std::uint8_t>(m);
day = static_cast<std::uint8_t>(d);
return true;
}
}
} // namespace detail
} // namespace mysql
} // namespace boost
#endif
+112
View File
@@ -0,0 +1,112 @@
//
// 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_CONCEPTS_HPP
#define BOOST_MYSQL_DETAIL_EXECUTION_CONCEPTS_HPP
#include <boost/mysql/statement.hpp>
#include <boost/mysql/string_view.hpp>
#include <boost/mysql/detail/config.hpp>
#include <type_traits>
#ifdef BOOST_MYSQL_HAS_CONCEPTS
namespace boost {
namespace mysql {
// Forward decls
template <class... StaticRow>
class static_execution_state;
template <class... StaticRow>
class static_results;
class execution_state;
class results;
namespace detail {
// Execution state
template <class T>
struct is_static_execution_state : std::false_type
{
};
template <class... T>
struct is_static_execution_state<static_execution_state<T...>> : std::true_type
{
};
template <class T>
concept execution_state_type = std::is_same_v<T, execution_state> || is_static_execution_state<T>::value;
// Results
template <class T>
struct is_static_results : std::false_type
{
};
template <class... T>
struct is_static_results<static_results<T...>> : std::true_type
{
};
template <class T>
concept results_type = std::is_same_v<T, results> || is_static_results<T>::value;
// Execution request
template <class T>
struct is_bound_statement_tuple : std::false_type
{
};
template <class T>
struct is_bound_statement_tuple<bound_statement_tuple<T>> : std::true_type
{
};
template <class T>
struct is_bound_statement_range : std::false_type
{
};
template <class T>
struct is_bound_statement_range<bound_statement_iterator_range<T>> : std::true_type
{
};
template <class T>
struct is_execution_request
{
using without_cvref = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
static constexpr bool value = std::is_convertible<T, string_view>::value ||
is_bound_statement_tuple<without_cvref>::value ||
is_bound_statement_range<without_cvref>::value;
};
template <class T>
concept execution_request = is_execution_request<T>::value;
} // namespace detail
} // namespace mysql
} // namespace boost
#define BOOST_MYSQL_EXECUTION_STATE_TYPE ::boost::mysql::detail::execution_state_type
#define BOOST_MYSQL_RESULTS_TYPE ::boost::mysql::detail::results_type
#define BOOST_MYSQL_EXECUTION_REQUEST ::boost::mysql::detail::execution_request
#else
#define BOOST_MYSQL_EXECUTION_STATE_TYPE class
#define BOOST_MYSQL_RESULTS_TYPE class
#define BOOST_MYSQL_EXECUTION_REQUEST class
#endif
#endif
@@ -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
+97
View File
@@ -0,0 +1,97 @@
//
// 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_FIELD_IMPL_HPP
#define BOOST_MYSQL_DETAIL_FIELD_IMPL_HPP
#include <boost/mysql/bad_field_access.hpp>
#include <boost/mysql/blob.hpp>
#include <boost/mysql/date.hpp>
#include <boost/mysql/datetime.hpp>
#include <boost/mysql/field_kind.hpp>
#include <boost/mysql/time.hpp>
#include <boost/mp11/algorithm.hpp>
#include <boost/throw_exception.hpp>
#include <boost/variant2/variant.hpp>
#include <string>
#include <type_traits>
namespace boost {
namespace mysql {
namespace detail {
// Breaks a circular dependency between field_view and field
struct field_impl
{
using null_t = boost::variant2::monostate;
using variant_type = boost::variant2::variant<
null_t, // Any of the below when the value is NULL
std::int64_t, // signed TINYINT, SMALLINT, MEDIUMINT, INT, BIGINT
std::uint64_t, // unsigned TINYINT, SMALLINT, MEDIUMINT, INT, BIGINT, YEAR, BIT
std::string, // CHAR, VARCHAR, TEXT (all sizes), , ENUM,
// SET, DECIMAL
blob, // BINARY, VARBINARY, BLOB (all sizes), GEOMETRY
float, // FLOAT
double, // DOUBLE
date, // DATE
datetime, // DATETIME, TIMESTAMP
time // TIME
>;
variant_type data;
field_impl() = default;
template <typename... Args>
field_impl(Args&&... args) noexcept(std::is_nothrow_constructible<variant_type, Args...>::value)
: data(std::forward<Args>(args)...)
{
}
field_kind kind() const noexcept { return static_cast<field_kind>(data.index()); }
template <typename T>
const T& as() const
{
const T* res = boost::variant2::get_if<T>(&data);
if (!res)
BOOST_THROW_EXCEPTION(bad_field_access());
return *res;
}
template <typename T>
T& as()
{
T* res = boost::variant2::get_if<T>(&data);
if (!res)
BOOST_THROW_EXCEPTION(bad_field_access());
return *res;
}
template <typename T>
const T& get() const noexcept
{
constexpr auto I = mp11::mp_find<variant_type, T>::value;
return boost::variant2::unsafe_get<I>(data);
}
template <typename T>
T& get() noexcept
{
constexpr auto I = mp11::mp_find<variant_type, T>::value;
return boost::variant2::unsafe_get<I>(data);
}
};
} // namespace detail
} // namespace mysql
} // namespace boost
#endif
+49
View File
@@ -0,0 +1,49 @@
//
// 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_FLAGS_HPP
#define BOOST_MYSQL_DETAIL_FLAGS_HPP
#include <cstdint>
namespace boost {
namespace mysql {
namespace detail {
namespace column_flags {
constexpr std::uint16_t not_null = 1; // Field can't be NULL.
constexpr std::uint16_t pri_key = 2; // Field is part of a primary key.
constexpr std::uint16_t unique_key = 4; // Field is part of a unique key.
constexpr std::uint16_t multiple_key = 8; // Field is part of a key.
constexpr std::uint16_t blob = 16; // Field is a blob.
constexpr std::uint16_t unsigned_ = 32; // Field is unsigned.
constexpr std::uint16_t zerofill = 64; // Field is zerofill.
constexpr std::uint16_t binary = 128; // Field is binary.
constexpr std::uint16_t enum_ = 256; // field is an enum
constexpr std::uint16_t auto_increment = 512; // field is a autoincrement field
constexpr std::uint16_t timestamp = 1024; // Field is a timestamp.
constexpr std::uint16_t set = 2048; // field is a set
constexpr std::uint16_t no_default_value = 4096; // Field doesn't have default value.
constexpr std::uint16_t on_update_now = 8192; // Field is set to NOW on UPDATE.
constexpr std::uint16_t part_key = 16384; // Intern; Part of some key.
constexpr std::uint16_t num = 32768; // Field is num (for clients)
} // namespace column_flags
namespace status_flags {
constexpr std::uint32_t more_results = 8;
constexpr std::uint32_t out_params = 4096;
} // namespace status_flags
} // namespace detail
} // namespace mysql
} // namespace boost
#endif
+801
View File
@@ -0,0 +1,801 @@
//
// 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_NETWORK_ALGORITHMS_HPP
#define BOOST_MYSQL_DETAIL_NETWORK_ALGORITHMS_HPP
#include <boost/mysql/diagnostics.hpp>
#include <boost/mysql/error_code.hpp>
#include <boost/mysql/execution_state.hpp>
#include <boost/mysql/field_view.hpp>
#include <boost/mysql/handshake_params.hpp>
#include <boost/mysql/rows_view.hpp>
#include <boost/mysql/statement.hpp>
#include <boost/mysql/string_view.hpp>
#include <boost/mysql/detail/access.hpp>
#include <boost/mysql/detail/any_execution_request.hpp>
#include <boost/mysql/detail/channel_ptr.hpp>
#include <boost/mysql/detail/config.hpp>
#include <boost/mysql/detail/execution_processor/execution_processor.hpp>
#include <boost/mysql/detail/typing/get_type_index.hpp>
#include <boost/asio/any_completion_handler.hpp>
#include <boost/mp11/integer_sequence.hpp>
#include <array>
#include <cstddef>
namespace boost {
namespace mysql {
template <class... StaticRow>
class static_execution_state;
namespace detail {
class channel;
template <class T>
using any_handler = asio::any_completion_handler<void(error_code, T)>;
using any_void_handler = asio::any_completion_handler<void(error_code)>;
// execution helpers
template <class... T, std::size_t... I>
std::array<field_view, sizeof...(T)> tuple_to_array_impl(const std::tuple<T...>& t, mp11::index_sequence<I...>) noexcept
{
return std::array<field_view, sizeof...(T)>{{to_field(std::get<I>(t))...}};
}
template <class... T>
std::array<field_view, sizeof...(T)> tuple_to_array(const std::tuple<T...>& t) noexcept
{
return tuple_to_array_impl(t, mp11::make_index_sequence<sizeof...(T)>());
}
struct query_request_getter
{
any_execution_request value;
any_execution_request get() const noexcept { return value; }
};
inline query_request_getter make_request_getter(string_view q, channel&) noexcept
{
return query_request_getter{q};
}
struct stmt_it_request_getter
{
statement stmt;
span<const field_view> params; // Points into channel shared_fields()
any_execution_request get() const noexcept { return any_execution_request(stmt, params); }
};
template <class FieldViewFwdIterator>
inline stmt_it_request_getter make_request_getter(
const bound_statement_iterator_range<FieldViewFwdIterator>& req,
channel& chan
)
{
auto& impl = access::get_impl(req);
auto& shared_fields = get_shared_fields(chan);
shared_fields.assign(impl.first, impl.last);
return {impl.stmt, shared_fields};
}
template <std::size_t N>
struct stmt_tuple_request_getter
{
statement stmt;
std::array<field_view, N> params;
any_execution_request get() const noexcept { return any_execution_request(stmt, params); }
};
template <class WritableFieldTuple>
stmt_tuple_request_getter<std::tuple_size<WritableFieldTuple>::value>
make_request_getter(const bound_statement_tuple<WritableFieldTuple>& req, channel&)
{
auto& impl = access::get_impl(req);
return {impl.stmt, tuple_to_array(impl.params)};
}
//
// connect
//
BOOST_MYSQL_DECL
void connect_erased(
channel& chan,
const void* endpoint,
const handshake_params& params,
error_code& err,
diagnostics& diag
);
BOOST_MYSQL_DECL
void async_connect_erased(
channel& chan,
const void* endpoint,
const handshake_params& params,
diagnostics& diag,
any_void_handler handler
);
// Handles casting from the generic EndpointType we've got in the interface to the concrete endpoint type
template <class Stream>
void connect_interface(
channel& chan,
const typename Stream::lowest_layer_type::endpoint_type& ep,
const handshake_params& params,
error_code& err,
diagnostics& diag
)
{
connect_erased(chan, &ep, params, err, diag);
}
template <class Stream>
struct connect_initiation
{
template <class Handler>
void operator()(
Handler&& handler,
channel* chan,
const typename Stream::lowest_layer_type::endpoint_type& endpoint,
handshake_params params,
diagnostics* diag
)
{
async_connect_erased(*chan, &endpoint, params, *diag, std::forward<Handler>(handler));
}
};
template <class Stream, class CompletionToken>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code))
async_connect_interface(
channel& chan,
const typename Stream::lowest_layer_type::endpoint_type& endpoint,
const handshake_params& params,
diagnostics& diag,
CompletionToken&& token
)
{
return asio::async_initiate<CompletionToken, void(error_code)>(
connect_initiation<Stream>(),
token,
&chan,
endpoint,
params,
&diag
);
}
//
// handshake
//
BOOST_MYSQL_DECL
void handshake_erased(channel& channel, const handshake_params& params, error_code& err, diagnostics& diag);
BOOST_MYSQL_DECL
void async_handshake_erased(
channel& chan,
const handshake_params& params,
diagnostics& diag,
any_void_handler
);
inline void handshake_interface(
channel& channel,
const handshake_params& params,
error_code& err,
diagnostics& diag
)
{
handshake_erased(channel, params, err, diag);
}
struct handshake_initiation
{
template <class Handler>
void operator()(Handler&& handler, channel* chan, handshake_params params, diagnostics* diag)
{
async_handshake_erased(*chan, params, *diag, std::forward<Handler>(handler));
}
};
template <class CompletionToken>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code))
async_handshake_interface(
channel& chan,
const handshake_params& params,
diagnostics& diag,
CompletionToken&& token
)
{
return asio::async_initiate<CompletionToken, void(error_code)>(
handshake_initiation(),
token,
&chan,
params,
&diag
);
}
//
// execute
//
BOOST_MYSQL_DECL
void execute_erased(
channel& channel,
const any_execution_request& req,
execution_processor& output,
error_code& err,
diagnostics& diag
);
BOOST_MYSQL_DECL void async_execute_erased(
channel& chan,
const any_execution_request& req,
execution_processor& output,
diagnostics& diag,
any_void_handler handler
);
struct initiate_execute
{
template <class Handler, class ExecutionRequest>
void operator()(
Handler&& handler,
channel& chan,
const ExecutionRequest& req,
execution_processor& proc,
diagnostics& diag
)
{
auto getter = make_request_getter(req, chan);
async_execute_erased(chan, getter.get(), proc, diag, std::forward<Handler>(handler));
}
};
template <class ExecutionRequest, class ResultsType>
void execute_interface(
channel& channel,
const ExecutionRequest& req,
ResultsType& result,
error_code& err,
diagnostics& diag
)
{
auto getter = make_request_getter(req, channel);
execute_erased(channel, getter.get(), access::get_impl(result).get_interface(), err, diag);
}
template <class ExecutionRequest, class ResultsType, class CompletionToken>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code))
async_execute_interface(
channel& chan,
ExecutionRequest&& req,
ResultsType& result,
diagnostics& diag,
CompletionToken&& token
)
{
return asio::async_initiate<CompletionToken, void(error_code)>(
initiate_execute(),
token,
std::ref(chan),
std::forward<ExecutionRequest>(req),
std::ref(access::get_impl(result).get_interface()),
std::ref(diag)
);
}
//
// start_execution
//
BOOST_MYSQL_DECL
void start_execution_erased(
channel& channel,
const any_execution_request& req,
execution_processor& proc,
error_code& err,
diagnostics& diag
);
BOOST_MYSQL_DECL
void async_start_execution_erased(
channel& channel,
const any_execution_request& req,
execution_processor& proc,
diagnostics& diag,
any_void_handler handler
);
struct initiate_start_execution
{
template <class Handler, class ExecutionRequest>
void operator()(
Handler&& handler,
channel& chan,
const ExecutionRequest& req,
execution_processor& proc,
diagnostics& diag
)
{
auto getter = make_request_getter(req, chan);
async_start_execution_erased(chan, getter.get(), proc, diag, std::forward<Handler>(handler));
}
};
template <class ExecutionRequest, class ExecutionStateType>
void start_execution_interface(
channel& channel,
const ExecutionRequest& req,
ExecutionStateType& st,
error_code& err,
diagnostics& diag
)
{
auto getter = make_request_getter(req, channel);
start_execution_erased(channel, getter.get(), access::get_impl(st).get_interface(), err, diag);
}
template <class ExecutionRequest, class ExecutionStateType, class CompletionToken>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code))
async_start_execution_interface(
channel& chan,
ExecutionRequest&& req,
ExecutionStateType& st,
diagnostics& diag,
CompletionToken&& token
)
{
return asio::async_initiate<CompletionToken, void(error_code)>(
initiate_start_execution(),
token,
std::ref(chan),
std::forward<ExecutionRequest>(req),
std::ref(access::get_impl(st).get_interface()),
std::ref(diag)
);
}
//
// prepare_statement
//
BOOST_MYSQL_DECL
statement prepare_statement_erased(channel& chan, string_view stmt, error_code& err, diagnostics& diag);
BOOST_MYSQL_DECL void async_prepare_statement_erased(
channel& chan,
string_view stmt,
diagnostics& diag,
any_handler<statement> handler
);
struct prepare_statement_initiation
{
template <class Handler>
void operator()(Handler&& handler, channel* chan, string_view stmt_sql, diagnostics* diag)
{
async_prepare_statement_erased(*chan, stmt_sql, *diag, std::forward<Handler>(handler));
}
};
inline statement prepare_statement_interface(
channel& chan,
string_view stmt,
error_code& err,
diagnostics& diag
)
{
return prepare_statement_erased(chan, stmt, err, diag);
}
template <class CompletionToken>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(boost::mysql::error_code, boost::mysql::statement))
async_prepare_statement_interface(channel& chan, string_view stmt, diagnostics& diag, CompletionToken&& token)
{
return asio::async_initiate<CompletionToken, void(error_code, statement)>(
prepare_statement_initiation(),
token,
&chan,
stmt,
&diag
);
}
//
// close_statement
//
BOOST_MYSQL_DECL
void close_statement_erased(channel& chan, const statement& stmt, error_code& err, diagnostics& diag);
BOOST_MYSQL_DECL
void async_close_statement_erased(
channel& chan,
const statement& stmt,
diagnostics& diag,
any_void_handler handler
);
struct close_statement_initiation
{
template <class Handler>
void operator()(Handler&& handler, channel* chan, statement stmt, diagnostics* diag)
{
async_close_statement_erased(*chan, stmt, *diag, std::forward<Handler>(handler));
}
};
inline void close_statement_interface(
channel& chan,
const statement& stmt,
error_code& err,
diagnostics& diag
)
{
close_statement_erased(chan, stmt, err, diag);
}
template <class CompletionToken>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code))
async_close_statement_interface(
channel& chan,
const statement& stmt,
diagnostics& diag,
CompletionToken&& token
)
{
return asio::async_initiate<CompletionToken, void(error_code)>(
close_statement_initiation(),
token,
&chan,
stmt,
&diag
);
}
//
// read_some_rows (dynamic)
//
BOOST_MYSQL_DECL
rows_view read_some_rows_dynamic_erased(
channel& chan,
execution_state_impl& st,
error_code& err,
diagnostics& diag
);
BOOST_MYSQL_DECL void async_read_some_rows_dynamic_erased(
channel& chan,
execution_state_impl& st,
diagnostics& diag,
any_handler<rows_view> handler
);
struct read_some_rows_dynamic_initiation
{
template <class Handler>
void operator()(Handler&& handler, channel* chan, execution_state_impl* st, diagnostics* diag)
{
async_read_some_rows_dynamic_erased(*chan, *st, *diag, std::forward<Handler>(handler));
}
};
inline rows_view read_some_rows_dynamic_interface(
channel& chan,
execution_state& st,
error_code& err,
diagnostics& diag
)
{
return read_some_rows_dynamic_erased(chan, access::get_impl(st), err, diag);
}
template <class CompletionToken>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code, rows_view))
async_read_some_rows_dynamic_interface(
channel& chan,
execution_state& st,
diagnostics& diag,
CompletionToken&& token
)
{
return asio::async_initiate<CompletionToken, void(error_code, rows_view)>(
read_some_rows_dynamic_initiation(),
token,
&chan,
&access::get_impl(st).get_interface(),
&diag
);
}
//
// read_some_rows (static)
//
BOOST_MYSQL_DECL
std::size_t read_some_rows_static_erased(
channel& chan,
execution_processor& proc,
const output_ref& output,
error_code& err,
diagnostics& diag
);
BOOST_MYSQL_DECL
void async_read_some_rows_erased(
channel& chan,
execution_processor& proc,
const output_ref& output,
diagnostics& diag,
any_handler<std::size_t> handler
);
template <class SpanRowType, class... RowType>
std::size_t read_some_rows_static_interface(
channel& chan,
static_execution_state<RowType...>& st,
span<SpanRowType> output,
error_code& err,
diagnostics& diag
)
{
constexpr std::size_t index = get_type_index<SpanRowType, RowType...>();
static_assert(index != index_not_found, "SpanRowType must be one of the types returned by the query");
return read_some_rows_static_erased(
chan,
access::get_impl(st).get_interface(),
output_ref(output, index),
err,
diag
);
}
struct read_some_rows_static_initiation
{
template <class Handler>
void operator()(
Handler&& handler,
channel* chan,
execution_processor* proc,
const output_ref& output,
diagnostics* diag
)
{
async_read_some_rows_erased(*chan, *proc, output, *diag, std::forward<Handler>(handler));
}
};
template <
class SpanRowType,
class... RowType,
BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code, std::size_t)) CompletionToken>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code, rows_view))
async_read_some_rows_static_interface(
channel& chan,
static_execution_state<RowType...>& st,
span<SpanRowType> output,
diagnostics& diag,
CompletionToken&& token
)
{
constexpr std::size_t index = get_type_index<SpanRowType, RowType...>();
static_assert(index != index_not_found, "SpanRowType must be one of the types returned by the query");
return asio::async_initiate<CompletionToken, void(error_code, std::size_t)>(
read_some_rows_static_initiation(),
token,
&chan,
&access::get_impl(st).get_interface(),
output_ref(output, index),
&diag
);
}
//
// read_resultset_head
//
BOOST_MYSQL_DECL
void read_resultset_head_erased(
channel& channel,
execution_processor& proc,
error_code& err,
diagnostics& diag
);
BOOST_MYSQL_DECL
void async_read_resultset_head_erased(
channel& chan,
execution_processor& proc,
diagnostics& diag,
any_void_handler handler
);
template <class ExecutionStateType>
void read_resultset_head_interface(
channel& channel,
ExecutionStateType& st,
error_code& err,
diagnostics& diag
)
{
read_resultset_head_erased(channel, access::get_impl(st).get_interface(), err, diag);
}
struct read_resultset_head_initiation
{
template <class Handler>
void operator()(Handler&& handler, channel* chan, execution_processor* proc, diagnostics* diag)
{
async_read_resultset_head_erased(*chan, *proc, *diag, std::forward<Handler>(handler));
}
};
template <class CompletionToken, class ExecutionStateType>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code))
async_read_resultset_head_interface(
channel& chan,
ExecutionStateType& st,
diagnostics& diag,
CompletionToken&& token
)
{
return asio::async_initiate<CompletionToken, void(error_code)>(
read_resultset_head_initiation(),
token,
&chan,
&access::get_impl(st).get_interface(),
&diag
);
}
//
// ping
//
BOOST_MYSQL_DECL
void ping_erased(channel& chan, error_code& code, diagnostics& diag);
BOOST_MYSQL_DECL
void async_ping_erased(channel& chan, diagnostics& diag, any_void_handler handler);
struct ping_initiation
{
template <class Handler>
void operator()(Handler&& handler, channel* chan, diagnostics* diag)
{
async_ping_erased(*chan, *diag, std::forward<Handler>(handler));
}
};
inline void ping_interface(channel& chan, error_code& code, diagnostics& diag)
{
ping_erased(chan, code, diag);
}
template <class CompletionToken>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code))
async_ping_interface(channel& chan, diagnostics& diag, CompletionToken&& token)
{
return asio::async_initiate<CompletionToken, void(error_code)>(ping_initiation(), token, &chan, &diag);
}
//
// reset_connection
//
BOOST_MYSQL_DECL
void reset_connection_erased(channel& chan, error_code& code, diagnostics& diag);
BOOST_MYSQL_DECL
void async_reset_connection_erased(channel& chan, diagnostics& diag, any_void_handler handler);
struct reset_connection_initiation
{
template <class Handler>
void operator()(Handler&& handler, channel* chan, diagnostics* diag)
{
async_reset_connection_erased(*chan, *diag, std::forward<Handler>(handler));
}
};
inline void reset_connection_interface(channel& chan, error_code& code, diagnostics& diag)
{
reset_connection_erased(chan, code, diag);
}
template <class CompletionToken>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code))
async_reset_connection_interface(channel& chan, diagnostics& diag, CompletionToken&& token)
{
return asio::async_initiate<CompletionToken, void(error_code)>(
reset_connection_initiation(),
token,
&chan,
&diag
);
}
//
// close connection
//
BOOST_MYSQL_DECL
void close_connection_erased(channel& chan, error_code& code, diagnostics& diag);
BOOST_MYSQL_DECL
void async_close_connection_erased(channel& chan, diagnostics& diag, any_void_handler handler);
struct close_connection_initiation
{
template <class Handler>
void operator()(Handler&& handler, channel* chan, diagnostics* diag)
{
async_close_connection_erased(*chan, *diag, std::forward<Handler>(handler));
}
};
inline void close_connection_interface(channel& chan, error_code& code, diagnostics& diag)
{
close_connection_erased(chan, code, diag);
}
template <class CompletionToken>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code))
async_close_connection_interface(channel& chan, diagnostics& diag, CompletionToken&& token)
{
return asio::async_initiate<CompletionToken, void(error_code)>(
close_connection_initiation(),
token,
&chan,
&diag
);
}
//
// quit connection
//
BOOST_MYSQL_DECL
void quit_connection_erased(channel& chan, error_code& err, diagnostics& diag);
BOOST_MYSQL_DECL
void async_quit_connection_erased(channel& chan, diagnostics& diag, any_void_handler handler);
struct quit_connection_initiation
{
template <class Handler>
void operator()(Handler&& handler, channel* chan, diagnostics* diag)
{
async_quit_connection_erased(*chan, *diag, std::forward<Handler>(handler));
}
};
inline void quit_connection_interface(channel& chan, error_code& err, diagnostics& diag)
{
quit_connection_erased(chan, err, diag);
}
template <class CompletionToken>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void(error_code))
async_quit_connection_interface(channel& chan, diagnostics& diag, CompletionToken&& token)
{
return asio::async_initiate<CompletionToken, void(error_code)>(
quit_connection_initiation(),
token,
&chan,
&diag
);
}
} // namespace detail
} // namespace mysql
} // namespace boost
#ifdef BOOST_MYSQL_HEADER_ONLY
#include <boost/mysql/impl/network_algorithms.ipp>
#endif
#endif
+37
View File
@@ -0,0 +1,37 @@
//
// 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_OK_VIEW_HPP
#define BOOST_MYSQL_DETAIL_OK_VIEW_HPP
#include <boost/mysql/string_view.hpp>
#include <boost/mysql/detail/flags.hpp>
#include <cstdint>
namespace boost {
namespace mysql {
namespace detail {
struct ok_view
{
std::uint64_t affected_rows;
std::uint64_t last_insert_id;
std::uint16_t status_flags;
std::uint16_t warnings;
string_view info;
bool more_results() const noexcept { return status_flags & status_flags::more_results; }
bool is_out_params() const noexcept { return status_flags & status_flags::out_params; }
};
} // namespace detail
} // namespace mysql
} // namespace boost
#endif
+34
View File
@@ -0,0 +1,34 @@
//
// 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_REBIND_EXECUTOR_HPP
#define BOOST_MYSQL_DETAIL_REBIND_EXECUTOR_HPP
#include <boost/asio/ssl/stream.hpp>
namespace boost {
namespace mysql {
namespace detail {
// This is required because ssl::stream doesn't have a rebind_executor member type
template <class Stream, class Executor>
struct rebind_executor
{
using type = typename Stream::template rebind_executor<Executor>::other;
};
template <class Stream, class Executor>
struct rebind_executor<boost::asio::ssl::stream<Stream>, Executor>
{
using type = boost::asio::ssl::stream<typename rebind_executor<Stream, Executor>::type>;
};
} // namespace detail
} // namespace mysql
} // namespace boost
#endif
+99
View File
@@ -0,0 +1,99 @@
//
// 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_RESULTS_ITERATOR_HPP
#define BOOST_MYSQL_DETAIL_RESULTS_ITERATOR_HPP
#include <boost/mysql/resultset.hpp>
#include <boost/mysql/resultset_view.hpp>
#include <boost/mysql/detail/access.hpp>
#include <boost/mysql/detail/execution_processor/results_impl.hpp>
namespace boost {
namespace mysql {
namespace detail {
class results_iterator
{
const results_impl* self_{};
std::size_t index_{};
public:
using value_type = resultset;
using reference = resultset_view;
using pointer = resultset_view;
using difference_type = std::ptrdiff_t;
using iterator_category = std::random_access_iterator_tag;
results_iterator() = default;
results_iterator(const results_impl* self, std::size_t index) noexcept : self_(self), index_(index) {}
results_iterator& operator++() noexcept
{
++index_;
return *this;
}
results_iterator operator++(int) noexcept
{
auto res = *this;
++(*this);
return res;
}
results_iterator& operator--() noexcept
{
--index_;
return *this;
}
results_iterator operator--(int) noexcept
{
auto res = *this;
--(*this);
return res;
}
results_iterator& operator+=(std::ptrdiff_t n) noexcept
{
index_ += n;
return *this;
}
results_iterator& operator-=(std::ptrdiff_t n) noexcept
{
index_ -= n;
return *this;
}
results_iterator operator+(std::ptrdiff_t n) const noexcept
{
return results_iterator(self_, index_ + n);
}
results_iterator operator-(std::ptrdiff_t n) const noexcept { return *this + (-n); }
std::ptrdiff_t operator-(results_iterator rhs) const noexcept { return index_ - rhs.index_; }
pointer operator->() const noexcept { return **this; }
reference operator*() const noexcept { return (*this)[0]; }
reference operator[](std::ptrdiff_t i) const noexcept
{
return access::construct<resultset_view>(*self_, index_ + i);
}
bool operator==(results_iterator rhs) const noexcept { return index_ == rhs.index_; }
bool operator!=(results_iterator rhs) const noexcept { return !(*this == rhs); }
bool operator<(results_iterator rhs) const noexcept { return index_ < rhs.index_; }
bool operator<=(results_iterator rhs) const noexcept { return index_ <= rhs.index_; }
bool operator>(results_iterator rhs) const noexcept { return index_ > rhs.index_; }
bool operator>=(results_iterator rhs) const noexcept { return index_ >= rhs.index_; }
std::size_t index() const noexcept { return index_; }
const results_impl* obj() const noexcept { return self_; }
};
inline results_iterator operator+(std::ptrdiff_t n, results_iterator it) noexcept { return it + n; }
} // namespace detail
} // namespace mysql
} // namespace boost
#endif
+25
View File
@@ -0,0 +1,25 @@
//
// 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_RESULTSET_ENCODING_HPP
#define BOOST_MYSQL_DETAIL_RESULTSET_ENCODING_HPP
namespace boost {
namespace mysql {
namespace detail {
enum class resultset_encoding
{
text,
binary
};
} // namespace detail
} // namespace mysql
} // namespace boost
#endif /* INCLUDE_BOOST_MYSQL_DETAIL_NETWORK_ALGORITHMS_COMMON_HPP_ */
+95
View File
@@ -0,0 +1,95 @@
//
// 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_ROW_IMPL_HPP
#define BOOST_MYSQL_DETAIL_ROW_IMPL_HPP
#include <boost/mysql/field_view.hpp>
#include <boost/mysql/detail/config.hpp>
#include <boost/core/span.hpp>
#include <cstddef>
#include <vector>
namespace boost {
namespace mysql {
namespace detail {
// Adds num_fields default-constructed fields to the vector, return pointer to the first
// allocated value. Used to allocate fields before deserialization
inline span<field_view> add_fields(std::vector<field_view>& storage, std::size_t num_fields)
{
std::size_t old_size = storage.size();
storage.resize(old_size + num_fields);
return span<field_view>(storage.data() + old_size, num_fields);
}
// A field_view vector with strings pointing into a
// single character buffer. Used to implement owning row types
class row_impl
{
public:
row_impl() = default;
BOOST_MYSQL_DECL
row_impl(const row_impl&);
row_impl(row_impl&&) = default;
BOOST_MYSQL_DECL
row_impl& operator=(const row_impl&);
row_impl& operator=(row_impl&&) = default;
~row_impl() = default;
// Copies the given span into *this
BOOST_MYSQL_DECL
row_impl(const field_view* fields, std::size_t size);
// Copies the given span into *this, used by row/rows in assignment from view
BOOST_MYSQL_DECL
void assign(const field_view* fields, std::size_t size);
// Adds new default constructed fields to provide storage to deserialization
span<field_view> add_fields(std::size_t num_fields)
{
return ::boost::mysql::detail::add_fields(fields_, num_fields);
}
// Saves strings in the [first, first+num_fields) range into the string buffer, used by execute
BOOST_MYSQL_DECL
void copy_strings_as_offsets(std::size_t first, std::size_t num_fields);
// Restores any offsets into string views, used by execute
BOOST_MYSQL_DECL
void offsets_to_string_views();
const std::vector<field_view>& fields() const noexcept { return fields_; }
void clear() noexcept
{
fields_.clear();
string_buffer_.clear();
}
private:
std::vector<field_view> fields_;
std::vector<unsigned char> string_buffer_;
};
} // namespace detail
} // namespace mysql
} // namespace boost
#ifdef BOOST_MYSQL_HEADER_ONLY
#include <boost/mysql/impl/row_impl.ipp>
#endif
#endif
+112
View File
@@ -0,0 +1,112 @@
//
// 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_ROWS_ITERATOR_HPP
#define BOOST_MYSQL_DETAIL_ROWS_ITERATOR_HPP
#include <boost/mysql/field_view.hpp>
#include <boost/mysql/row.hpp>
#include <boost/mysql/row_view.hpp>
#include <boost/mysql/detail/access.hpp>
#include <cstddef>
#include <cstdint>
#include <iterator>
namespace boost {
namespace mysql {
namespace detail {
inline row_view row_slice(const field_view* fields, std::size_t num_columns, std::size_t offset) noexcept
{
return access::construct<row_view>(fields + num_columns * offset, num_columns);
}
class rows_iterator
{
const field_view* fields_{nullptr};
std::size_t num_columns_{0};
std::size_t row_num_{0};
public:
using value_type = row;
using reference = row_view;
using pointer = row_view;
using difference_type = std::ptrdiff_t;
using iterator_category = std::random_access_iterator_tag;
rows_iterator() = default;
rows_iterator(const field_view* fields, std::size_t num_columns, std::size_t rownum) noexcept
: fields_(fields), num_columns_(num_columns), row_num_(rownum)
{
}
rows_iterator& operator++() noexcept
{
++row_num_;
return *this;
}
rows_iterator operator++(int) noexcept
{
auto res = *this;
++(*this);
return res;
}
rows_iterator& operator--() noexcept
{
--row_num_;
return *this;
}
rows_iterator operator--(int) noexcept
{
auto res = *this;
--(*this);
return res;
}
rows_iterator& operator+=(std::ptrdiff_t n) noexcept
{
row_num_ += n;
return *this;
}
rows_iterator& operator-=(std::ptrdiff_t n) noexcept
{
row_num_ -= n;
return *this;
}
rows_iterator operator+(std::ptrdiff_t n) const noexcept
{
return rows_iterator(fields_, num_columns_, row_num_ + n);
}
rows_iterator operator-(std::ptrdiff_t n) const noexcept
{
return rows_iterator(fields_, num_columns_, row_num_ - n);
}
std::ptrdiff_t operator-(rows_iterator rhs) const noexcept { return row_num_ - rhs.row_num_; }
pointer operator->() const noexcept { return **this; }
reference operator*() const noexcept { return (*this)[0]; }
reference operator[](std::ptrdiff_t i) const noexcept
{
return row_slice(fields_, num_columns_, row_num_ + i);
}
bool operator==(rows_iterator rhs) const noexcept { return row_num_ == rhs.row_num_; }
bool operator!=(rows_iterator rhs) const noexcept { return !(*this == rhs); }
bool operator<(rows_iterator rhs) const noexcept { return row_num_ < rhs.row_num_; }
bool operator<=(rows_iterator rhs) const noexcept { return row_num_ <= rhs.row_num_; }
bool operator>(rows_iterator rhs) const noexcept { return row_num_ > rhs.row_num_; }
bool operator>=(rows_iterator rhs) const noexcept { return row_num_ >= rhs.row_num_; }
};
inline rows_iterator operator+(std::ptrdiff_t n, rows_iterator it) noexcept { return it + n; }
} // namespace detail
} // namespace mysql
} // namespace boost
#endif
+52
View File
@@ -0,0 +1,52 @@
//
// 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_SOCKET_STREAM_HPP
#define BOOST_MYSQL_DETAIL_SOCKET_STREAM_HPP
#include <boost/asio/basic_socket.hpp>
#include <boost/asio/basic_stream_socket.hpp>
#include <type_traits>
namespace boost {
namespace mysql {
namespace detail {
template <class T>
struct is_socket : std::false_type
{
};
// typename basic_stream_socket::lowest_layer_type is basic_socket, so we accept basic_socket and
// basic_stream_socket here
template <class Protocol, class Executor>
struct is_socket<asio::basic_socket<Protocol, Executor>> : std::true_type
{
};
template <class Protocol, class Executor>
struct is_socket<asio::basic_stream_socket<Protocol, Executor>> : std::true_type
{
};
template <class T, class = void>
struct is_socket_stream : std::false_type
{
};
template <class T>
struct is_socket_stream<T, typename std::enable_if<is_socket<typename T::lowest_layer_type>::value>::type>
: std::true_type
{
};
} // namespace detail
} // namespace mysql
} // namespace boost
#endif
+35
View File
@@ -0,0 +1,35 @@
//
// 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_STRING_VIEW_OFFSET_HPP
#define BOOST_MYSQL_DETAIL_STRING_VIEW_OFFSET_HPP
#include <cstddef>
namespace boost {
namespace mysql {
namespace detail {
// Represents a string_view using offsets into a buffer.
// Useful during deserialization, for buffers that may reallocate.
struct string_view_offset
{
std::size_t offset;
std::size_t size;
constexpr bool operator==(string_view_offset rhs) const noexcept
{
return offset == rhs.offset && size == rhs.size;
}
constexpr bool operator!=(string_view_offset rhs) const noexcept { return !(*this == rhs); }
};
} // namespace detail
} // namespace mysql
} // namespace boost
#endif
+33
View File
@@ -0,0 +1,33 @@
//
// 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_THROW_ON_ERROR_LOC_HPP
#define BOOST_MYSQL_DETAIL_THROW_ON_ERROR_LOC_HPP
#include <boost/mysql/diagnostics.hpp>
#include <boost/mysql/error_code.hpp>
#include <boost/mysql/error_with_diagnostics.hpp>
#include <boost/assert/source_location.hpp>
namespace boost {
namespace mysql {
namespace detail {
inline void throw_on_error_loc(error_code err, const diagnostics& diag, const boost::source_location& loc)
{
if (err)
{
::boost::throw_exception(error_with_diagnostics(err, diag), loc);
}
}
} // namespace detail
} // namespace mysql
} // namespace boost
#endif
+32
View File
@@ -0,0 +1,32 @@
//
// 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_TYPING_GET_TYPE_INDEX_HPP
#define BOOST_MYSQL_DETAIL_TYPING_GET_TYPE_INDEX_HPP
#include <boost/mp11/algorithm.hpp>
#include <boost/mp11/list.hpp>
namespace boost {
namespace mysql {
namespace detail {
constexpr std::size_t index_not_found = static_cast<std::size_t>(-1);
template <class SpanRowType, class... RowType>
constexpr std::size_t get_type_index() noexcept
{
using lunique = mp11::mp_unique<mp11::mp_list<RowType...>>;
using index_t = mp11::mp_find<lunique, SpanRowType>;
return index_t::value < mp11::mp_size<lunique>::value ? index_t::value : index_not_found;
}
} // namespace detail
} // namespace mysql
} // namespace boost
#endif
+135
View File
@@ -0,0 +1,135 @@
//
// 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_TYPING_META_CHECK_CONTEXT_HPP
#define BOOST_MYSQL_DETAIL_TYPING_META_CHECK_CONTEXT_HPP
#include <boost/mysql/client_errc.hpp>
#include <boost/mysql/column_type.hpp>
#include <boost/mysql/diagnostics.hpp>
#include <boost/mysql/error_code.hpp>
#include <boost/mysql/metadata.hpp>
#include <boost/mysql/metadata_collection_view.hpp>
#include <boost/mysql/string_view.hpp>
#include <boost/mysql/detail/access.hpp>
#include <boost/mysql/detail/config.hpp>
#include <boost/mysql/detail/typing/pos_map.hpp>
#include <memory>
#include <sstream>
namespace boost {
namespace mysql {
namespace detail {
inline const char* column_type_to_str(const metadata& meta) noexcept
{
switch (meta.type())
{
case column_type::tinyint: return meta.is_unsigned() ? "TINYINT UNSIGNED" : "TINYINT";
case column_type::smallint: return meta.is_unsigned() ? "SMALLINT UNSIGNED" : "SMALLINT";
case column_type::mediumint: return meta.is_unsigned() ? "MEDIUMINT UNSIGNED" : "MEDIUMINT";
case column_type::int_: return meta.is_unsigned() ? "INT UNSIGNED" : "INT";
case column_type::bigint: return meta.is_unsigned() ? "BIGINT UNSIGNED" : "BIGINT";
case column_type::float_: return "FLOAT";
case column_type::double_: return "DOUBLE";
case column_type::decimal: return "DECIMAL";
case column_type::bit: return "BIT";
case column_type::year: return "YEAR";
case column_type::time: return "TIME";
case column_type::date: return "DATE";
case column_type::datetime: return "DATETIME";
case column_type::timestamp: return "TIMESTAMP";
case column_type::char_: return "CHAR";
case column_type::varchar: return "VARCHAR";
case column_type::binary: return "BINARY";
case column_type::varbinary: return "VARBINARY";
case column_type::text: return "TEXT";
case column_type::blob: return "BLOB";
case column_type::enum_: return "ENUM";
case column_type::set: return "SET";
case column_type::json: return "JSON";
case column_type::geometry: return "GEOMETRY";
default: return "<unknown column type>";
}
}
class meta_check_context
{
std::unique_ptr<std::ostringstream> errors_;
std::size_t current_index_{};
span<const std::size_t> pos_map_;
name_table_t name_table_;
metadata_collection_view meta_{};
bool nullability_checked_{};
std::ostringstream& add_error()
{
if (!errors_)
errors_.reset(new std::ostringstream);
else
*errors_ << '\n';
return *errors_;
}
void insert_field_name(std::ostringstream& os)
{
if (has_field_names(name_table_))
os << "'" << name_table_[current_index_] << "'";
else
os << "in position " << current_index_;
}
public:
meta_check_context(
span<const std::size_t> pos_map,
name_table_t name_table,
metadata_collection_view meta
) noexcept
: pos_map_(pos_map), name_table_(name_table), meta_(meta)
{
}
// Accessors
const metadata& current_meta() const noexcept { return map_metadata(pos_map_, current_index_, meta_); }
bool is_current_field_absent() const noexcept { return pos_map_[current_index_] == pos_absent; }
// Iteration
void advance() noexcept
{
nullability_checked_ = false;
++current_index_;
}
// Nullability
void set_nullability_checked() noexcept { nullability_checked_ = true; }
bool nullability_checked() const noexcept { return nullability_checked_; }
// Error reporting
BOOST_MYSQL_DECL
void add_field_absent_error();
BOOST_MYSQL_DECL
void add_type_mismatch_error(const char* cpp_type_name);
BOOST_MYSQL_DECL
void add_nullability_error();
BOOST_MYSQL_DECL
error_code check_errors(diagnostics& diag) const;
};
} // namespace detail
} // namespace mysql
} // namespace boost
#ifdef BOOST_MYSQL_HEADER_ONLY
#include <boost/mysql/impl/meta_check_context.ipp>
#endif
#endif
+92
View File
@@ -0,0 +1,92 @@
//
// 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_TYPING_POS_MAP_HPP
#define BOOST_MYSQL_DETAIL_TYPING_POS_MAP_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/assert.hpp>
#include <boost/core/span.hpp>
#include <cstddef>
namespace boost {
namespace mysql {
namespace detail {
// These functions map C++ type positions to positions to positions in the DB query
constexpr std::size_t pos_absent = static_cast<std::size_t>(-1);
using name_table_t = boost::span<const string_view>;
inline bool has_field_names(name_table_t name_table) noexcept { return !name_table.empty(); }
inline void pos_map_reset(span<std::size_t> self) noexcept
{
for (std::size_t i = 0; i < self.size(); ++i)
self.data()[i] = pos_absent;
}
inline void pos_map_add_field(
span<std::size_t> self,
name_table_t name_table,
std::size_t db_index,
string_view field_name
) noexcept
{
if (has_field_names(name_table))
{
BOOST_ASSERT(self.size() == name_table.size());
// We're mapping fields by name. Try to find where in our target struct
// is the current field located
auto it = std::find(name_table.begin(), name_table.end(), field_name);
if (it != name_table.end())
{
std::size_t cpp_index = it - name_table.begin();
self[cpp_index] = db_index;
}
}
else
{
// We're mapping by position. Any extra trailing fields are discarded
if (db_index < self.size())
{
self[db_index] = db_index;
}
}
}
inline field_view map_field_view(
span<const std::size_t> self,
std::size_t cpp_index,
span<const field_view> array
) noexcept
{
BOOST_ASSERT(cpp_index < self.size());
return array[self[cpp_index]];
}
inline const metadata& map_metadata(
span<const std::size_t> self,
std::size_t cpp_index,
metadata_collection_view meta
) noexcept
{
BOOST_ASSERT(cpp_index < self.size());
return meta[self[cpp_index]];
}
} // namespace detail
} // namespace mysql
} // namespace boost
#endif
+622
View File
@@ -0,0 +1,622 @@
//
// 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_TYPING_READABLE_FIELD_TRAITS_HPP
#define BOOST_MYSQL_DETAIL_TYPING_READABLE_FIELD_TRAITS_HPP
#include <boost/mysql/client_errc.hpp>
#include <boost/mysql/date.hpp>
#include <boost/mysql/datetime.hpp>
#include <boost/mysql/diagnostics.hpp>
#include <boost/mysql/error_code.hpp>
#include <boost/mysql/field_kind.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/time.hpp>
#include <boost/mysql/detail/config.hpp>
#include <boost/mysql/detail/typing/meta_check_context.hpp>
#include <boost/mysql/detail/typing/pos_map.hpp>
#include <boost/mysql/detail/void_t.hpp>
#include <cstdint>
#include <limits>
#include <string>
#include <type_traits>
namespace boost {
namespace mysql {
namespace detail {
// Helpers for integers
template <class SignedInt>
error_code parse_signed_int(field_view input, SignedInt& output)
{
using unsigned_t = typename std::make_unsigned<SignedInt>::type;
using limits_t = std::numeric_limits<SignedInt>;
auto kind = input.kind();
if (kind == field_kind::int64)
{
auto v = input.get_int64();
if (v < (limits_t::min)() || v > (limits_t::max)())
{
return client_errc::static_row_parsing_error;
}
output = static_cast<SignedInt>(v);
return error_code();
}
else if (kind == field_kind::uint64)
{
auto v = input.get_uint64();
if (v > static_cast<unsigned_t>((limits_t::max)()))
{
return client_errc::static_row_parsing_error;
}
output = static_cast<SignedInt>(v);
return error_code();
}
else
{
return client_errc::static_row_parsing_error;
}
}
template <class UnsignedInt>
error_code parse_unsigned_int(field_view input, UnsignedInt& output)
{
if (input.kind() != field_kind::uint64)
{
return client_errc::static_row_parsing_error;
}
auto v = input.get_uint64();
if (v > (std::numeric_limits<UnsignedInt>::max)())
{
return client_errc::static_row_parsing_error;
}
output = static_cast<UnsignedInt>(v);
return error_code();
}
// We want all integer types to be allowed as fields. Some integers
// may have the same width as others, but different type (e.g. long and long long
// may both be 64-bit, but different types). Auxiliar int_traits to allow this to work
template <class T, bool is_signed = std::is_signed<T>::value, std::size_t width = sizeof(T)>
struct int_traits
{
static constexpr bool is_supported = false;
};
template <class T>
struct int_traits<T, true, 1>
{
static constexpr bool is_supported = true;
static constexpr const char* type_name = "int8_t";
static bool meta_check(meta_check_context& ctx)
{
switch (ctx.current_meta().type())
{
case column_type::tinyint: return !ctx.current_meta().is_unsigned();
default: return false;
}
}
static error_code parse(field_view input, T& output) { return parse_signed_int(input, output); }
};
template <class T>
struct int_traits<T, false, 1>
{
static constexpr bool is_supported = true;
static constexpr const char* type_name = "uint8_t";
static bool meta_check(meta_check_context& ctx)
{
switch (ctx.current_meta().type())
{
case column_type::tinyint: return ctx.current_meta().is_unsigned();
default: return false;
}
}
static error_code parse(field_view input, T& output) { return parse_unsigned_int(input, output); }
};
template <class T>
struct int_traits<T, true, 2>
{
static constexpr bool is_supported = true;
static constexpr const char* type_name = "int16_t";
static bool meta_check(meta_check_context& ctx)
{
switch (ctx.current_meta().type())
{
case column_type::tinyint: return true;
case column_type::smallint:
case column_type::year: return !ctx.current_meta().is_unsigned();
default: return false;
}
}
static error_code parse(field_view input, T& output) { return parse_signed_int(input, output); }
};
template <class T>
struct int_traits<T, false, 2>
{
static constexpr bool is_supported = true;
static constexpr const char* type_name = "uint16_t";
static bool meta_check(meta_check_context& ctx)
{
switch (ctx.current_meta().type())
{
case column_type::tinyint:
case column_type::smallint:
case column_type::year: return ctx.current_meta().is_unsigned();
default: return false;
}
}
static error_code parse(field_view input, T& output) { return parse_unsigned_int(input, output); }
};
template <class T>
struct int_traits<T, true, 4>
{
static constexpr bool is_supported = true;
static constexpr const char* type_name = "int32_t";
static bool meta_check(meta_check_context& ctx)
{
switch (ctx.current_meta().type())
{
case column_type::tinyint:
case column_type::smallint:
case column_type::year:
case column_type::mediumint: return true;
case column_type::int_: return !ctx.current_meta().is_unsigned();
default: return false;
}
}
static error_code parse(field_view input, T& output) { return parse_signed_int(input, output); }
};
template <class T>
struct int_traits<T, false, 4>
{
static constexpr bool is_supported = true;
static constexpr const char* type_name = "uint32_t";
static bool meta_check(meta_check_context& ctx)
{
switch (ctx.current_meta().type())
{
case column_type::tinyint:
case column_type::smallint:
case column_type::year:
case column_type::mediumint:
case column_type::int_: return ctx.current_meta().is_unsigned();
default: return false;
}
}
static error_code parse(field_view input, T& output) { return parse_unsigned_int(input, output); }
};
template <class T>
struct int_traits<T, true, 8>
{
static constexpr bool is_supported = true;
static constexpr const char* type_name = "int64_t";
static bool meta_check(meta_check_context& ctx)
{
switch (ctx.current_meta().type())
{
case column_type::tinyint:
case column_type::smallint:
case column_type::year:
case column_type::mediumint:
case column_type::int_: return true;
case column_type::bigint: return !ctx.current_meta().is_unsigned();
default: return false;
}
}
static error_code parse(field_view input, T& output) { return parse_signed_int(input, output); }
};
template <class T>
struct int_traits<T, false, 8>
{
static constexpr bool is_supported = true;
static constexpr const char* type_name = "uint64_t";
static bool meta_check(meta_check_context& ctx)
{
switch (ctx.current_meta().type())
{
case column_type::tinyint:
case column_type::smallint:
case column_type::year:
case column_type::mediumint:
case column_type::int_:
case column_type::bigint: return ctx.current_meta().is_unsigned();
case column_type::bit: return true;
default: return false;
}
}
static error_code parse(field_view input, std::uint64_t& output)
{
return parse_unsigned_int(input, output);
}
};
// Traits
template <typename T, class EnableIf = void>
struct readable_field_traits
{
static constexpr bool is_supported = false;
};
template <>
struct readable_field_traits<char, void> : int_traits<char>
{
};
template <>
struct readable_field_traits<signed char, void> : int_traits<signed char>
{
};
template <>
struct readable_field_traits<unsigned char, void> : int_traits<unsigned char>
{
};
template <>
struct readable_field_traits<short, void> : int_traits<short>
{
};
template <>
struct readable_field_traits<unsigned short, void> : int_traits<unsigned short>
{
};
template <>
struct readable_field_traits<int, void> : int_traits<int>
{
};
template <>
struct readable_field_traits<unsigned int, void> : int_traits<unsigned int>
{
};
template <>
struct readable_field_traits<long, void> : int_traits<long>
{
};
template <>
struct readable_field_traits<unsigned long, void> : int_traits<unsigned long>
{
};
template <>
struct readable_field_traits<long long, void> : int_traits<long long>
{
};
template <>
struct readable_field_traits<unsigned long long, void> : int_traits<unsigned long long>
{
};
template <>
struct readable_field_traits<bool, void>
{
static constexpr bool is_supported = true;
static constexpr const char* type_name = "bool";
static bool meta_check(meta_check_context& ctx)
{
return ctx.current_meta().type() == column_type::tinyint && !ctx.current_meta().is_unsigned();
}
static error_code parse(field_view input, bool& output)
{
if (input.kind() != field_kind::int64)
{
return client_errc::static_row_parsing_error;
}
output = input.get_int64() != 0;
return error_code();
}
};
template <>
struct readable_field_traits<float, void>
{
static constexpr bool is_supported = true;
static constexpr const char* type_name = "float";
static bool meta_check(meta_check_context& ctx)
{
return ctx.current_meta().type() == column_type::float_;
}
static error_code parse(field_view input, float& output)
{
if (input.kind() != field_kind::float_)
{
return client_errc::static_row_parsing_error;
}
output = input.get_float();
return error_code();
}
};
template <>
struct readable_field_traits<double, void>
{
static constexpr bool is_supported = true;
static constexpr const char* type_name = "double";
static bool meta_check(meta_check_context& ctx)
{
switch (ctx.current_meta().type())
{
case column_type::float_:
case column_type::double_: return true;
default: return false;
}
}
static error_code parse(field_view input, double& output)
{
auto kind = input.kind();
if (kind == field_kind::float_)
{
output = input.get_float();
return error_code();
}
else if (kind == field_kind::double_)
{
output = input.get_double();
return error_code();
}
else
{
return client_errc::static_row_parsing_error;
}
}
};
template <class Allocator>
struct readable_field_traits<std::basic_string<char, std::char_traits<char>, Allocator>, void>
{
static constexpr bool is_supported = true;
static constexpr const char* type_name = "string";
static bool meta_check(meta_check_context& ctx)
{
switch (ctx.current_meta().type())
{
case column_type::decimal:
case column_type::char_:
case column_type::varchar:
case column_type::text:
case column_type::enum_:
case column_type::set:
case column_type::json: return true;
default: return false;
}
}
static error_code parse(
field_view input,
std::basic_string<char, std::char_traits<char>, Allocator>& output
)
{
if (input.kind() != field_kind::string)
{
return client_errc::static_row_parsing_error;
}
output = input.get_string();
return error_code();
}
};
template <class Allocator>
struct readable_field_traits<std::vector<unsigned char, Allocator>, void>
{
static constexpr bool is_supported = true;
static constexpr const char* type_name = "blob";
static bool meta_check(meta_check_context& ctx)
{
switch (ctx.current_meta().type())
{
case column_type::binary:
case column_type::varbinary:
case column_type::blob:
case column_type::geometry:
case column_type::unknown: return true;
default: return false;
}
}
static error_code parse(field_view input, std::vector<unsigned char, Allocator>& output)
{
if (input.kind() != field_kind::blob)
{
return client_errc::static_row_parsing_error;
}
auto view = input.get_blob();
output.assign(view.begin(), view.end());
return error_code();
}
};
template <>
struct readable_field_traits<date, void>
{
static constexpr bool is_supported = true;
static constexpr const char* type_name = "date";
static bool meta_check(meta_check_context& ctx) { return ctx.current_meta().type() == column_type::date; }
static error_code parse(field_view input, date& output)
{
if (input.kind() != field_kind::date)
{
return client_errc::static_row_parsing_error;
}
output = input.get_date();
return error_code();
}
};
template <>
struct readable_field_traits<datetime, void>
{
static constexpr bool is_supported = true;
static constexpr const char* type_name = "datetime";
static bool meta_check(meta_check_context& ctx)
{
switch (ctx.current_meta().type())
{
case column_type::datetime:
case column_type::timestamp: return true;
default: return false;
}
}
static error_code parse(field_view input, datetime& output)
{
if (input.kind() != field_kind::datetime)
{
return client_errc::static_row_parsing_error;
}
output = input.get_datetime();
return error_code();
}
};
template <>
struct readable_field_traits<time, void>
{
static constexpr bool is_supported = true;
static constexpr const char* type_name = "time";
static bool meta_check(meta_check_context& ctx) { return ctx.current_meta().type() == column_type::time; }
static error_code parse(field_view input, time& output)
{
if (input.kind() != field_kind::time)
{
return client_errc::static_row_parsing_error;
}
output = input.get_time();
return error_code();
}
};
// std::optional<T> and boost::optional<T>. To avoid dependencies,
// this is achieved through a "concept"
template <class T, class = void>
struct is_readable_optional : std::false_type
{
};
template <class T>
struct is_readable_optional<
T,
void_t<
typename std::enable_if<
std::is_same<decltype(std::declval<T&>().value()), typename T::value_type&>::value>::type,
decltype(std::declval<T&>().emplace()), // T should be default constructible
decltype(std::declval<T&>().reset())>> : std::true_type
{
};
template <class T>
struct readable_field_traits<
T,
typename std::enable_if<
is_readable_optional<T>::value && readable_field_traits<typename T::value_type>::is_supported>::type>
{
using value_type = typename T::value_type;
static constexpr bool is_supported = true;
static constexpr const char* type_name = readable_field_traits<value_type>::type_name;
static bool meta_check(meta_check_context& ctx)
{
ctx.set_nullability_checked();
return readable_field_traits<value_type>::meta_check(ctx);
}
static error_code parse(field_view input, T& output)
{
if (input.is_null())
{
output.reset();
return error_code();
}
else
{
output.emplace();
return readable_field_traits<value_type>::parse(input, output.value());
}
}
};
template <class T>
struct is_readable_field
{
static constexpr bool value = readable_field_traits<T>::is_supported;
};
template <typename ReadableField>
void meta_check_field_impl(meta_check_context& ctx)
{
using traits_t = readable_field_traits<ReadableField>;
// Verify that the field is present
if (ctx.is_current_field_absent())
{
ctx.add_field_absent_error();
return;
}
// Perform the check
bool ok = traits_t::meta_check(ctx);
if (!ok)
{
ctx.add_type_mismatch_error(traits_t::type_name);
}
// Check nullability
if (!ctx.nullability_checked() && !ctx.current_meta().is_not_null())
{
ctx.add_nullability_error();
}
}
template <typename ReadableField>
void meta_check_field(meta_check_context& ctx)
{
static_assert(is_readable_field<ReadableField>::value, "Should be a ReadableField");
meta_check_field_impl<ReadableField>(ctx);
ctx.advance();
}
struct meta_check_field_fn
{
meta_check_context ctx;
template <class T>
void operator()(T)
{
meta_check_field<typename T::type>(ctx);
}
};
template <typename ReadableFieldList>
error_code meta_check_field_type_list(
span<const std::size_t> field_map,
name_table_t name_table,
metadata_collection_view meta,
diagnostics& diag
)
{
meta_check_field_fn fn{meta_check_context(field_map, name_table, meta)};
boost::mp11::mp_for_each<ReadableFieldList>(fn);
return fn.ctx.check_errors(diag);
}
} // namespace detail
} // namespace mysql
} // namespace boost
#endif
+269
View File
@@ -0,0 +1,269 @@
//
// 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_TYPING_ROW_TRAITS_HPP
#define BOOST_MYSQL_DETAIL_TYPING_ROW_TRAITS_HPP
#include <boost/mysql/detail/config.hpp>
#ifdef BOOST_MYSQL_CXX14
#include <boost/mysql/client_errc.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/typing/meta_check_context.hpp>
#include <boost/mysql/detail/typing/pos_map.hpp>
#include <boost/mysql/detail/typing/readable_field_traits.hpp>
#include <boost/assert.hpp>
#include <boost/describe/members.hpp>
#include <boost/mp11/algorithm.hpp>
#include <boost/mp11/utility.hpp>
#include <cstddef>
#include <tuple>
#include <type_traits>
#include <utility>
namespace boost {
namespace mysql {
namespace detail {
// Helpers to check that all the fields satisfy ReadableField
// and produce meaningful error messages, with the offending field type, at least
// Workaround clang 3.6 not liking generic lambdas in the below constexpr function
struct readable_field_checker
{
template <class TypeIdentity>
constexpr void operator()(TypeIdentity) const noexcept
{
using T = typename TypeIdentity::type;
static_assert(
is_readable_field<T>::value,
"You're trying to use an unsupported field type in a row type. Review your row type definitions."
);
}
};
template <class TypeList>
static constexpr bool check_readable_field() noexcept
{
mp11::mp_for_each<TypeList>(readable_field_checker{});
return true;
}
// Workaround std::array::data not being constexpr in C++14
template <class T, std::size_t N>
struct array_wrapper
{
T data_[N];
constexpr boost::span<const T> span() const noexcept { return boost::span<const T>(data_); }
};
template <class T>
struct array_wrapper<T, 0>
{
struct
{
} data_; // allow empty brace initialization
constexpr boost::span<const T> span() const noexcept { return boost::span<const T>(); }
};
// Workaround for char_traits::length not being constexpr in C++14
// Only used to retrieve Describe member name lengths
constexpr std::size_t get_length(const char* s) noexcept
{
const char* p = s;
while (*p)
++p;
return p - s;
}
// Helpers
class parse_functor
{
span<const std::size_t> pos_map_;
span<const field_view> fields_;
std::size_t index_{};
error_code ec_;
public:
parse_functor(span<const std::size_t> pos_map, span<const field_view> fields) noexcept
: pos_map_(pos_map), fields_(fields)
{
}
template <class ReadableField>
void operator()(ReadableField& output)
{
auto ec = readable_field_traits<ReadableField>::parse(
map_field_view(pos_map_, index_++, fields_),
output
);
if (!ec_)
ec_ = ec;
}
error_code error() const noexcept { return ec_; }
};
// Base template
template <class T, bool is_describe_struct = boost::describe::has_describe_members<T>::value>
class row_traits;
// Describe structs
template <class DescribeStruct>
using row_members = boost::describe::
describe_members<DescribeStruct, boost::describe::mod_public | boost::describe::mod_inherited>;
template <class MemberDescriptor>
constexpr string_view get_member_name(MemberDescriptor d) noexcept
{
return string_view(d.name, get_length(d.name));
}
template <template <class...> class ListType, class... MemberDescriptor>
constexpr array_wrapper<string_view, sizeof...(MemberDescriptor)> get_describe_names(ListType<
MemberDescriptor...>)
{
return {{get_member_name(MemberDescriptor())...}};
}
template <class DescribeStruct>
constexpr auto describe_names_storage = get_describe_names(row_members<DescribeStruct>{});
template <class DescribeStruct>
class row_traits<DescribeStruct, true>
{
using members = row_members<DescribeStruct>;
template <class D>
struct descriptor_to_type
{
using helper = decltype(std::declval<DescribeStruct>().*std::declval<D>().pointer);
using type = typename std::remove_reference<helper>::type;
};
using member_types = mp11::mp_transform<descriptor_to_type, members>;
static_assert(check_readable_field<member_types>(), "");
public:
using types = member_types;
static constexpr std::size_t size() noexcept { return boost::mp11::mp_size<members>::value; }
static constexpr name_table_t name_table() noexcept
{
return describe_names_storage<DescribeStruct>.span();
}
static void parse(parse_functor& parser, DescribeStruct& to)
{
boost::mp11::mp_for_each<members>([&](auto D) { parser(to.*D.pointer); });
}
};
// Tuples
template <class T>
struct is_tuple : std::false_type
{
};
template <class... T>
struct is_tuple<std::tuple<T...>> : std::true_type
{
};
template <class... ReadableField>
class row_traits<std::tuple<ReadableField...>, false>
{
using tuple_type = std::tuple<ReadableField...>;
using field_types = boost::mp11::mp_list<boost::mp11::mp_identity<ReadableField>...>;
static_assert(check_readable_field<field_types>(), "");
public:
using types = field_types;
static constexpr std::size_t size() noexcept { return std::tuple_size<tuple_type>::value; }
static constexpr name_table_t name_table() noexcept { return name_table_t(); }
static void parse(parse_functor& parser, tuple_type& to) { boost::mp11::tuple_for_each(to, parser); }
};
// We want is_static_row to only inspect the shape of the row (i.e. it's a tuple vs. it's nothing we know),
// and not individual fields. These are static_assert-ed in individual row_traits. This gives us an error
// message that contains the offending types, at least.
template <class T>
struct is_static_row
{
static constexpr bool value = is_tuple<T>::value || describe::has_describe_members<T>::value;
};
#ifdef BOOST_MYSQL_HAS_CONCEPTS
template <class T>
concept static_row = is_static_row<T>::value;
#define BOOST_MYSQL_STATIC_ROW ::boost::mysql::detail::static_row
#else
#define BOOST_MYSQL_STATIC_ROW class
#endif
// External interface
template <BOOST_MYSQL_STATIC_ROW StaticRow>
constexpr std::size_t get_row_size()
{
return row_traits<StaticRow>::size();
}
template <BOOST_MYSQL_STATIC_ROW StaticRow>
constexpr name_table_t get_row_name_table()
{
return row_traits<StaticRow>::name_table();
}
template <BOOST_MYSQL_STATIC_ROW StaticRow>
error_code meta_check(span<const std::size_t> pos_map, metadata_collection_view meta, diagnostics& diag)
{
using fields = typename row_traits<StaticRow>::types;
BOOST_ASSERT(pos_map.size() == get_row_size<StaticRow>());
return meta_check_field_type_list<fields>(pos_map, get_row_name_table<StaticRow>(), meta, diag);
}
template <BOOST_MYSQL_STATIC_ROW StaticRow>
error_code parse(span<const std::size_t> pos_map, span<const field_view> from, StaticRow& to)
{
BOOST_ASSERT(pos_map.size() == get_row_size<StaticRow>());
BOOST_ASSERT(from.size() >= get_row_size<StaticRow>());
parse_functor ctx(pos_map, from);
row_traits<StaticRow>::parse(ctx, to);
return ctx.error();
}
using meta_check_fn_t =
error_code (*)(span<const std::size_t> field_map, metadata_collection_view meta, diagnostics& diag);
// For multi-resultset - helper
template <class... StaticRow>
constexpr std::size_t max_num_columns = (std::max)({get_row_size<StaticRow>()...});
} // namespace detail
} // namespace mysql
} // namespace boost
#endif // BOOST_MYSQL_CXX14
#endif
+22
View File
@@ -0,0 +1,22 @@
//
// 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_VOID_T_HPP
#define BOOST_MYSQL_DETAIL_VOID_T_HPP
namespace boost {
namespace mysql {
namespace detail {
template <typename...>
using void_t = void;
}
} // namespace mysql
} // namespace boost
#endif /* INCLUDE_BOOST_MYSQL_DETAIL_PROTOCOL_IMPL_SERIALIZATION_HPP_ */
+146
View File
@@ -0,0 +1,146 @@
//
// 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_WRITABLE_FIELD_TRAITS_HPP
#define BOOST_MYSQL_DETAIL_WRITABLE_FIELD_TRAITS_HPP
#include <boost/mysql/field_view.hpp>
#include <boost/mysql/detail/config.hpp>
#include <type_traits>
namespace boost {
namespace mysql {
namespace detail {
template <class T, class En1 = void, class En2 = void>
struct writable_field_traits
{
static constexpr bool is_supported = false;
};
template <>
struct writable_field_traits<bool, void, void>
{
static constexpr bool is_supported = true;
static field_view to_field(bool value) noexcept { return field_view(value ? 1 : 0); }
};
template <class T>
struct writable_field_traits<
T,
typename std::enable_if<std::is_constructible<field_view, const T&>::value>::type,
void>
{
static constexpr bool is_supported = true;
static field_view to_field(const T& value) noexcept { return field_view(value); }
};
// Optionals. To avoid dependencies, we use a "concept".
// We consider a type an optional if has a `bool has_value() const` and
// `const value_type& value() const`
template <class T>
struct writable_field_traits<
T,
void,
typename std::enable_if<
std::is_same<decltype(std::declval<const T&>().has_value()), bool>::value &&
std::is_same<decltype(std::declval<const T&>().value()), const typename T::value_type&>::value>::type>
{
using value_traits = writable_field_traits<typename T::value_type>;
static constexpr bool is_supported = value_traits::is_supported;
static field_view to_field(const T& value) noexcept
{
return value.has_value() ? value_traits::to_field(value.value()) : field_view();
}
};
template <class T>
field_view to_field(const T& value) noexcept
{
return writable_field_traits<T>::to_field(value);
}
template <class T>
struct is_writable_field
{
static constexpr bool value = writable_field_traits<T>::is_supported;
};
// field_view_forward_iterator
template <typename T, typename = void>
struct is_field_view_forward_iterator : std::false_type
{
};
// clang-format off
template <typename T>
struct is_field_view_forward_iterator<
T,
typename std::enable_if<
std::is_convertible<
typename std::iterator_traits<T>::reference,
field_view
>::value
&&
std::is_base_of<
std::forward_iterator_tag,
typename std::iterator_traits<T>::iterator_category
>::value
>::type
> : std::true_type { };
// clang-format on
#ifdef BOOST_MYSQL_HAS_CONCEPTS
template <class T>
concept field_view_forward_iterator = is_field_view_forward_iterator<T>::value;
#define BOOST_MYSQL_FIELD_VIEW_FORWARD_ITERATOR ::boost::mysql::detail::field_view_forward_iterator
#else // BOOST_MYSQL_HAS_CONCEPTS
#define BOOST_MYSQL_FIELD_VIEW_FORWARD_ITERATOR class
#endif // BOOST_MYSQL_HAS_CONCEPTS
// writable_field_tuple
template <class... T>
struct is_writable_field_tuple_impl : std::false_type
{
};
template <class... T>
struct is_writable_field_tuple_impl<std::tuple<T...>>
: mp11::mp_all_of<mp11::mp_list<T...>, is_writable_field>
{
};
template <class Tuple>
struct is_writable_field_tuple : is_writable_field_tuple_impl<typename std::decay<Tuple>::type>
{
};
#ifdef BOOST_MYSQL_HAS_CONCEPTS
template <class T>
concept writable_field_tuple = is_writable_field_tuple<T>::value;
#define BOOST_MYSQL_WRITABLE_FIELD_TUPLE ::boost::mysql::detail::writable_field_tuple
#else // BOOST_MYSQL_HAS_CONCEPTS
#define BOOST_MYSQL_WRITABLE_FIELD_TUPLE class
#endif // BOOST_MYSQL_HAS_CONCEPTS
} // namespace detail
} // namespace mysql
} // namespace boost
#endif