mirror of
https://github.com/vdemydiuk/mtapi.git
synced 2026-08-13 02:38:07 +00:00
Added thirdparty: boost library
This commit is contained in:
+44
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
Vendored
Executable
+217
@@ -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
|
||||
Vendored
Executable
+123
@@ -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
|
||||
+219
@@ -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
|
||||
Vendored
Executable
+295
@@ -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
|
||||
Vendored
Executable
+349
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
Reference in New Issue
Block a user