Added thirdparty: boost library

This commit is contained in:
Viacheslav Demydiuk
2024-01-06 19:55:56 +02:00
parent bf49f439e1
commit bccd1e7051
15683 changed files with 3239840 additions and 0 deletions
+55
View File
@@ -0,0 +1,55 @@
//
// 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_IMPL_INTERNAL_PROTOCOL_BASIC_TYPES_HPP
#define BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_BASIC_TYPES_HPP
#include <boost/mysql/string_view.hpp>
#include <array>
#include <cstdint>
namespace boost {
namespace mysql {
namespace detail {
struct int3
{
std::uint32_t value;
};
struct int_lenenc
{
std::uint64_t value;
};
struct string_null
{
string_view value;
};
struct string_eof
{
string_view value;
};
struct string_lenenc
{
string_view value;
};
template <std::size_t N>
struct string_fixed
{
std::array<char, N> value;
};
} // namespace detail
} // namespace mysql
} // namespace boost
#endif
@@ -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_IMPL_INTERNAL_PROTOCOL_BINARY_SERIALIZATION_HPP
#define BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_BINARY_SERIALIZATION_HPP
#include <boost/mysql/field_view.hpp>
#include <boost/mysql/detail/config.hpp>
#include <boost/mysql/impl/internal/protocol/serialization.hpp>
namespace boost {
namespace mysql {
namespace detail {
BOOST_MYSQL_DECL
std::size_t get_size(field_view input) noexcept;
BOOST_MYSQL_DECL
void serialize(serialization_context& ctx, field_view input) noexcept;
} // namespace detail
} // namespace mysql
} // namespace boost
#ifdef BOOST_MYSQL_HEADER_ONLY
#include <boost/mysql/impl/internal/protocol/binary_serialization.ipp>
#endif
#endif
@@ -0,0 +1,133 @@
//
// 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_IMPL_INTERNAL_PROTOCOL_BINARY_SERIALIZATION_IPP
#define BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_BINARY_SERIALIZATION_IPP
#pragma once
#include <boost/mysql/days.hpp>
#include <boost/mysql/detail/config.hpp>
#include <boost/mysql/impl/internal/protocol/binary_serialization.hpp>
#include <boost/mysql/impl/internal/protocol/constants.hpp>
#include <boost/mysql/impl/internal/protocol/serialization.hpp>
#include <chrono>
namespace boost {
namespace mysql {
namespace detail {
// Binary serialization
template <class T>
BOOST_MYSQL_STATIC_OR_INLINE void serialize_binary_float(serialization_context& ctx, T input)
{
boost::endian::endian_store<T, sizeof(T), boost::endian::order::little>(ctx.first(), input);
ctx.advance(sizeof(T));
}
BOOST_MYSQL_STATIC_OR_INLINE
void serialize_binary_date(serialization_context& ctx, const date& input)
{
using namespace binc;
serialize(ctx, static_cast<std::uint8_t>(date_sz), input.year(), input.month(), input.day());
}
BOOST_MYSQL_STATIC_OR_INLINE
void serialize_binary_datetime(serialization_context& ctx, const datetime& input)
{
using namespace binc;
// Serialize
serialize(
ctx,
static_cast<std::uint8_t>(datetime_dhmsu_sz),
input.year(),
input.month(),
input.day(),
input.hour(),
input.minute(),
input.second(),
input.microsecond()
);
}
BOOST_MYSQL_STATIC_OR_INLINE
void serialize_binary_time(serialization_context& ctx, const boost::mysql::time& input)
{
using namespace binc;
using boost::mysql::days;
using std::chrono::duration_cast;
using std::chrono::hours;
using std::chrono::microseconds;
using std::chrono::minutes;
using std::chrono::seconds;
// Break time
auto num_micros = duration_cast<microseconds>(input % seconds(1));
auto num_secs = duration_cast<seconds>(input % minutes(1) - num_micros);
auto num_mins = duration_cast<minutes>(input % hours(1) - num_secs);
auto num_hours = duration_cast<hours>(input % days(1) - num_mins);
auto num_days = duration_cast<days>(input - num_hours);
std::uint8_t is_negative = (input.count() < 0) ? 1 : 0;
// Serialize
serialize(
ctx,
static_cast<std::uint8_t>(time_dhmsu_sz),
is_negative,
static_cast<std::uint32_t>(std::abs(num_days.count())),
static_cast<std::uint8_t>(std::abs(num_hours.count())),
static_cast<std::uint8_t>(std::abs(num_mins.count())),
static_cast<std::uint8_t>(std::abs(num_secs.count())),
static_cast<std::uint32_t>(std::abs(num_micros.count()))
);
}
} // namespace detail
} // namespace mysql
} // namespace boost
std::size_t boost::mysql::detail::get_size(field_view input) noexcept
{
switch (input.kind())
{
case field_kind::null: return 0;
case field_kind::int64: return 8;
case field_kind::uint64: return 8;
case field_kind::string: return get_size(string_lenenc{input.get_string()});
case field_kind::blob: return get_size(string_lenenc{to_string(input.get_blob())});
case field_kind::float_: return 4;
case field_kind::double_: return 8;
case field_kind::date: return binc::date_sz + binc::length_sz;
case field_kind::datetime: return binc::datetime_dhmsu_sz + binc::length_sz;
case field_kind::time: return binc::time_dhmsu_sz + binc::length_sz;
default: BOOST_ASSERT(false); return 0;
}
}
void boost::mysql::detail::serialize(serialization_context& ctx, field_view input) noexcept
{
switch (input.kind())
{
case field_kind::null: break;
case field_kind::int64: serialize(ctx, input.get_int64()); break;
case field_kind::uint64: serialize(ctx, input.get_uint64()); break;
case field_kind::string: serialize(ctx, string_lenenc{input.get_string()}); break;
case field_kind::blob: serialize(ctx, string_lenenc{to_string(input.get_blob())}); break;
case field_kind::float_: serialize_binary_float(ctx, input.get_float()); break;
case field_kind::double_: serialize_binary_float(ctx, input.get_double()); break;
case field_kind::date: serialize_binary_date(ctx, input.get_date()); break;
case field_kind::datetime: serialize_binary_datetime(ctx, input.get_datetime()); break;
case field_kind::time: serialize_binary_time(ctx, input.get_time()); break;
default: BOOST_ASSERT(false); break;
}
}
#endif
@@ -0,0 +1,47 @@
//
// 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_IMPL_INTERNAL_PROTOCOL_BIT_DESERIALIZATION_HPP
#define BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_BIT_DESERIALIZATION_HPP
#include <boost/mysql/field_view.hpp>
#include <boost/mysql/string_view.hpp>
#include <boost/mysql/impl/internal/protocol/serialization.hpp>
#include <boost/endian/conversion.hpp>
#include <cstring>
namespace boost {
namespace mysql {
namespace detail {
// All BIT values come as binary values between 1 and 8 bytes length packed in string_lenenc's,
// for both the text and the binary protocols. As the text protocol already unpacks the
// string_lenenc layer, this function is in charge of just parsing the binary payload. The length of
// the BIT value depends on how the type was defined in the table (e.g. BIT(14) will send a 2 byte
// value; BIT(54) will send a 7 byte one). Values are sent as big-endian.
inline deserialize_errc deserialize_bit(string_view from, field_view& to) noexcept
{
std::size_t num_bytes = from.size();
if (num_bytes < 1 || num_bytes > 8)
{
return deserialize_errc::protocol_value_error;
}
unsigned char temp[8]{};
unsigned char* dest = temp + sizeof(temp) - num_bytes;
std::memcpy(dest, from.data(), num_bytes);
to = field_view(endian::load_big_u64(temp));
return deserialize_errc::ok;
}
} // namespace detail
} // namespace mysql
} // namespace boost
#endif
+130
View File
@@ -0,0 +1,130 @@
//
// 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_IMPL_INTERNAL_PROTOCOL_CAPABILITIES_HPP
#define BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_CAPABILITIES_HPP
#include <cstdint>
namespace boost {
namespace mysql {
namespace detail {
// Server/client capabilities
// clang-format off
constexpr std::uint32_t CLIENT_LONG_PASSWORD = 1; // Use the improved version of Old Password Authentication
constexpr std::uint32_t CLIENT_FOUND_ROWS = 2; // Send found rows instead of affected rows in EOF_Packet
constexpr std::uint32_t CLIENT_LONG_FLAG = 4; // Get all column flags
constexpr std::uint32_t CLIENT_CONNECT_WITH_DB = 8; // Database (schema) name can be specified on connect in Handshake Response Packet
constexpr std::uint32_t CLIENT_NO_SCHEMA = 16; // Don't allow database.table.column
constexpr std::uint32_t CLIENT_COMPRESS = 32; // Compression protocol supported
constexpr std::uint32_t CLIENT_ODBC = 64; // Special handling of ODBC behavior
constexpr std::uint32_t CLIENT_LOCAL_FILES = 128; // Can use LOAD DATA LOCAL
constexpr std::uint32_t CLIENT_IGNORE_SPACE = 256; // Ignore spaces before '('
constexpr std::uint32_t CLIENT_PROTOCOL_41 = 512; // New 4.1 protocol
constexpr std::uint32_t CLIENT_INTERACTIVE = 1024; // This is an interactive client
constexpr std::uint32_t CLIENT_SSL = 2048; // Use SSL encryption for the session
constexpr std::uint32_t CLIENT_IGNORE_SIGPIPE = 4096; // Client only flag
constexpr std::uint32_t CLIENT_TRANSACTIONS = 8192; // Client knows about transactions
constexpr std::uint32_t CLIENT_RESERVED = 16384; // DEPRECATED: Old flag for 4.1 protocol
constexpr std::uint32_t CLIENT_SECURE_CONNECTION = 32768; // DEPRECATED: Old flag for 4.1 authentication, required by MariaDB
constexpr std::uint32_t CLIENT_MULTI_STATEMENTS = (1UL << 16); // Enable/disable multi-stmt support
constexpr std::uint32_t CLIENT_MULTI_RESULTS = (1UL << 17); // Enable/disable multi-results
constexpr std::uint32_t CLIENT_PS_MULTI_RESULTS = (1UL << 18); // Multi-results and OUT parameters in PS-protocol
constexpr std::uint32_t CLIENT_PLUGIN_AUTH = (1UL << 19); // Client supports plugin authentication
constexpr std::uint32_t CLIENT_CONNECT_ATTRS = (1UL << 20); // Client supports connection attributes
constexpr std::uint32_t CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA = (1UL << 21); // Enable authentication response packet to be larger than 255 bytes
constexpr std::uint32_t CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS = (1UL << 22); // Don't close the connection for a user account with expired password
constexpr std::uint32_t CLIENT_SESSION_TRACK = (1UL << 23); // Capable of handling server state change information
constexpr std::uint32_t CLIENT_DEPRECATE_EOF = (1UL << 24); // Client no longer needs EOF_Packet and will use OK_Packet instead
constexpr std::uint32_t CLIENT_SSL_VERIFY_SERVER_CERT = (1UL << 30); // Verify server certificate
constexpr std::uint32_t CLIENT_OPTIONAL_RESULTSET_METADATA = (1UL << 25); // The client can handle optional metadata information in the resultset
constexpr std::uint32_t CLIENT_REMEMBER_OPTIONS = (1UL << 31); // Don't reset the options after an unsuccessful connect
// clang-format on
class capabilities
{
std::uint32_t value_;
public:
constexpr explicit capabilities(std::uint32_t value = 0) noexcept : value_(value){};
constexpr std::uint32_t get() const noexcept { return value_; }
void set(std::uint32_t value) noexcept { value_ = value; }
constexpr bool has(std::uint32_t cap) const noexcept { return value_ & cap; }
constexpr bool has_all(capabilities other) const noexcept
{
return (value_ & other.get()) == other.get();
}
constexpr capabilities operator|(capabilities rhs) const noexcept
{
return capabilities(value_ | rhs.value_);
}
constexpr capabilities operator&(capabilities rhs) const noexcept
{
return capabilities(value_ & rhs.value_);
}
constexpr bool operator==(const capabilities& rhs) const noexcept { return value_ == rhs.value_; }
constexpr bool operator!=(const capabilities& rhs) const noexcept { return value_ != rhs.value_; }
};
/*
* CLIENT_LONG_PASSWORD: unset // Use the improved version of Old Password Authentication
* CLIENT_FOUND_ROWS: unset // Send found rows instead of affected rows in EOF_Packet
* CLIENT_LONG_FLAG: unset // Get all column flags
* CLIENT_CONNECT_WITH_DB: optional // Database (schema) name can be specified on connect in
* Handshake Response Packet CLIENT_NO_SCHEMA: unset // Don't allow database.table.column
* CLIENT_COMPRESS: unset // Compression protocol supported
* CLIENT_ODBC: unset // Special handling of ODBC behavior
* CLIENT_LOCAL_FILES: unset // Can use LOAD DATA LOCAL
* CLIENT_IGNORE_SPACE: unset // Ignore spaces before '('
* CLIENT_PROTOCOL_41: mandatory // New 4.1 protocol
* CLIENT_INTERACTIVE: unset // This is an interactive client
* CLIENT_SSL: unset // Use SSL encryption for the session
* CLIENT_IGNORE_SIGPIPE: unset // Client only flag
* CLIENT_TRANSACTIONS: unset // Client knows about transactions
* CLIENT_RESERVED: unset // DEPRECATED: Old flag for 4.1 protocol
* CLIENT_RESERVED2: unset // DEPRECATED: Old flag for 4.1 authentication
* \ CLIENT_SECURE_CONNECTION CLIENT_MULTI_STATEMENTS: unset // Enable/disable multi-stmt support
* CLIENT_MULTI_RESULTS: unset // Enable/disable multi-results
* CLIENT_PS_MULTI_RESULTS: unset // Multi-results and OUT parameters in PS-protocol
* CLIENT_PLUGIN_AUTH: mandatory // Client supports plugin authentication
* CLIENT_CONNECT_ATTRS: unset // Client supports connection attributes
* CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA: mandatory // Enable authentication response packet to be
* larger than 255 bytes CLIENT_CAN_HANDLE_EXPIRED_PASSWORDS: unset // Don't close the connection
* for a user account with expired password CLIENT_SESSION_TRACK: unset // Capable of handling
* server state change information CLIENT_DEPRECATE_EOF: mandatory // Client no longer needs
* EOF_Packet and will use OK_Packet instead CLIENT_SSL_VERIFY_SERVER_CERT: unset // Verify server
* certificate CLIENT_OPTIONAL_RESULTSET_METADATA: unset // The client can handle optional metadata
* information in the resultset CLIENT_REMEMBER_OPTIONS: unset // Don't reset the options after an
* unsuccessful connect
*
* We pay attention to:
* CLIENT_CONNECT_WITH_DB: optional // Database (schema) name can be specified on connect in
* Handshake Response Packet CLIENT_PROTOCOL_41: mandatory // New 4.1 protocol CLIENT_PLUGIN_AUTH:
* mandatory // Client supports plugin authentication CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA:
* mandatory // Enable authentication response packet to be larger than 255 bytes
* CLIENT_DEPRECATE_EOF: mandatory // Client no longer needs EOF_Packet and will use OK_Packet
* instead
*/
// clang-format off
constexpr capabilities mandatory_capabilities{
CLIENT_PROTOCOL_41 |
CLIENT_PLUGIN_AUTH |
CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA |
CLIENT_DEPRECATE_EOF |
CLIENT_SECURE_CONNECTION
};
// clang-format on
constexpr capabilities optional_capabilities{CLIENT_MULTI_RESULTS | CLIENT_PS_MULTI_RESULTS};
} // namespace detail
} // namespace mysql
} // namespace boost
#endif
+65
View File
@@ -0,0 +1,65 @@
//
// 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_IMPL_INTERNAL_PROTOCOL_CONSTANTS_HPP
#define BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_CONSTANTS_HPP
#include <cstddef>
#include <cstdint>
namespace boost {
namespace mysql {
namespace detail {
constexpr std::size_t MAX_PACKET_SIZE = 0xffffff;
constexpr std::size_t HEADER_SIZE = 4;
// The binary collation number, used to distinguish blobs from strings
constexpr std::uint16_t binary_collation = 63;
// Prepared statements
namespace cursor_types {
constexpr std::uint8_t no_cursor = 0;
constexpr std::uint8_t read_only = 1;
constexpr std::uint8_t for_update = 2;
constexpr std::uint8_t scrollable = 4;
} // namespace cursor_types
// Binary protocol (de)serialization constants
namespace binc {
constexpr std::size_t length_sz = 1; // length byte, for date, datetime and time
constexpr std::size_t year_sz = 2;
constexpr std::size_t month_sz = 1;
constexpr std::size_t date_day_sz = 1;
constexpr std::size_t time_days_sz = 4;
constexpr std::size_t hours_sz = 1;
constexpr std::size_t mins_sz = 1;
constexpr std::size_t secs_sz = 1;
constexpr std::size_t micros_sz = 4;
constexpr std::size_t time_sign_sz = 1;
constexpr std::size_t date_sz = year_sz + month_sz + date_day_sz; // does not include length
constexpr std::size_t datetime_d_sz = date_sz;
constexpr std::size_t datetime_dhms_sz = datetime_d_sz + hours_sz + mins_sz + secs_sz;
constexpr std::size_t datetime_dhmsu_sz = datetime_dhms_sz + micros_sz;
constexpr std::size_t time_dhms_sz = time_sign_sz + time_days_sz + hours_sz + mins_sz + secs_sz;
constexpr std::size_t time_dhmsu_sz = time_dhms_sz + micros_sz;
constexpr std::size_t time_max_days = 34; // equivalent to the 839 hours, in the broken format
} // namespace binc
} // namespace detail
} // namespace mysql
} // namespace boost
#endif
+25
View File
@@ -0,0 +1,25 @@
//
// Copyright (c) 2019-2023 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_DB_FLAVOR_HPP
#define BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_DB_FLAVOR_HPP
namespace boost {
namespace mysql {
namespace detail {
enum class db_flavor
{
mysql,
mariadb
};
} // namespace detail
} // namespace mysql
} // namespace boost
#endif
@@ -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_IMPL_INTERNAL_PROTOCOL_DESERIALIZE_BINARY_FIELD_HPP
#define BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_DESERIALIZE_BINARY_FIELD_HPP
#include <boost/mysql/field_view.hpp>
#include <boost/mysql/metadata.hpp>
#include <boost/mysql/detail/config.hpp>
#include <boost/mysql/impl/internal/protocol/serialization.hpp>
namespace boost {
namespace mysql {
namespace detail {
BOOST_MYSQL_DECL
deserialize_errc deserialize_binary_field(
deserialization_context& ctx,
const metadata& meta,
field_view& output
);
} // namespace detail
} // namespace mysql
} // namespace boost
#ifdef BOOST_MYSQL_HEADER_ONLY
#include <boost/mysql/impl/internal/protocol/deserialize_binary_field.ipp>
#endif
#endif /* INCLUDE_BOOST_MYSQL_DETAIL_PROTOCOL_BINARY_DESERIALIZATION_HPP_ */
@@ -0,0 +1,319 @@
//
// 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_IMPL_INTERNAL_PROTOCOL_DESERIALIZE_BINARY_FIELD_IPP
#define BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_DESERIALIZE_BINARY_FIELD_IPP
#pragma once
#include <boost/mysql/field_kind.hpp>
#include <boost/mysql/field_view.hpp>
#include <boost/mysql/metadata.hpp>
#include <boost/mysql/detail/config.hpp>
#include <boost/mysql/detail/datetime.hpp>
#include <boost/mysql/impl/internal/protocol/bit_deserialization.hpp>
#include <boost/mysql/impl/internal/protocol/constants.hpp>
#include <boost/mysql/impl/internal/protocol/deserialize_binary_field.hpp>
#include <boost/mysql/impl/internal/protocol/serialization.hpp>
#include <cmath>
#include <cstddef>
namespace boost {
namespace mysql {
namespace detail {
// strings
BOOST_MYSQL_STATIC_OR_INLINE
deserialize_errc deserialize_binary_field_string(
deserialization_context& ctx,
field_view& output,
bool is_blob
) noexcept
{
string_lenenc deser;
auto err = deserialize(ctx, deser);
if (err != deserialize_errc::ok)
return err;
if (is_blob)
{
output = field_view(
blob_view(reinterpret_cast<const unsigned char*>(deser.value.data()), deser.value.size())
);
}
else
{
output = field_view(deser.value);
}
return deserialize_errc::ok;
}
// ints
template <class TargetType, class DeserializableType>
BOOST_MYSQL_STATIC_OR_INLINE deserialize_errc
deserialize_binary_field_int_impl(deserialization_context& ctx, field_view& output) noexcept
{
DeserializableType deser;
auto err = deserialize(ctx, deser);
if (err != deserialize_errc::ok)
return err;
output = field_view(static_cast<TargetType>(deser));
return deserialize_errc::ok;
}
template <class DeserializableTypeUnsigned, class DeserializableTypeSigned>
BOOST_MYSQL_STATIC_OR_INLINE deserialize_errc
deserialize_binary_field_int(const metadata& meta, deserialization_context& ctx, field_view& output) noexcept
{
return meta.is_unsigned()
? deserialize_binary_field_int_impl<std::uint64_t, DeserializableTypeUnsigned>(ctx, output)
: deserialize_binary_field_int_impl<std::int64_t, DeserializableTypeSigned>(ctx, output);
}
// Bits. These come as a binary value between 1 and 8 bytes,
// packed in a string
BOOST_MYSQL_STATIC_OR_INLINE deserialize_errc
deserialize_binary_field_bit(deserialization_context& ctx, field_view& output) noexcept
{
string_lenenc buffer;
auto err = deserialize(ctx, buffer);
if (err != deserialize_errc::ok)
return err;
return boost::mysql::detail::deserialize_bit(buffer.value, output);
}
// Floats
template <class T>
BOOST_MYSQL_STATIC_OR_INLINE deserialize_errc
deserialize_binary_field_float(deserialization_context& ctx, field_view& output) noexcept
{
// Size check
if (!ctx.enough_size(sizeof(T)))
return deserialize_errc::incomplete_message;
// Endianness conversion. Boost.Endian support for floats start at 1.71
T v = boost::endian::endian_load<T, sizeof(T), boost::endian::order::little>(ctx.first());
// Nans and infs not allowed in SQL
if (std::isnan(v) || std::isinf(v))
return deserialize_errc::protocol_value_error;
// Done
ctx.advance(sizeof(T));
output = field_view(v);
return deserialize_errc::ok;
}
// Time types
BOOST_MYSQL_STATIC_OR_INLINE
deserialize_errc deserialize_binary_ymd(deserialization_context& ctx, boost::mysql::date& output)
{
using namespace boost::mysql::detail;
std::uint16_t year;
std::uint8_t month;
std::uint8_t day;
// Deserialize
auto err = deserialize(ctx, year, month, day);
if (err != deserialize_errc::ok)
return err;
// Range check
if (year > max_year || month > max_month || day > max_day)
{
return deserialize_errc::protocol_value_error;
}
output = boost::mysql::date(year, month, day);
return deserialize_errc::ok;
}
BOOST_MYSQL_STATIC_OR_INLINE
deserialize_errc deserialize_binary_field_date(deserialization_context& ctx, field_view& output) noexcept
{
using namespace boost::mysql::detail::binc;
// Deserialize length
std::uint8_t length;
auto err = deserialize(ctx, length);
if (err != deserialize_errc::ok)
return err;
// Check for zero dates
if (length < date_sz)
{
output = field_view(boost::mysql::date());
return deserialize_errc::ok;
}
// Deserialize rest of fields
boost::mysql::date d;
err = deserialize_binary_ymd(ctx, d);
if (err != deserialize_errc::ok)
return err;
output = field_view(d);
return deserialize_errc::ok;
}
BOOST_MYSQL_STATIC_OR_INLINE
deserialize_errc deserialize_binary_field_datetime(deserialization_context& ctx, field_view& output) noexcept
{
using namespace binc;
// Deserialize length
std::uint8_t length;
auto err = deserialize(ctx, length);
if (err != deserialize_errc::ok)
return err;
// If the DATETIME does not contain some of the values below,
// they are supposed to be zero
boost::mysql::date d{};
std::uint8_t hours = 0;
std::uint8_t minutes = 0;
std::uint8_t seconds = 0;
std::uint32_t micros = 0;
// Date part
if (length >= datetime_d_sz)
{
err = deserialize_binary_ymd(ctx, d);
if (err != deserialize_errc::ok)
return err;
}
// Hours, minutes, seconds
if (length >= datetime_dhms_sz)
{
err = deserialize(ctx, hours, minutes, seconds);
if (err != deserialize_errc::ok)
return err;
}
// Microseconds
if (length >= datetime_dhmsu_sz)
{
err = deserialize(ctx, micros);
if (err != deserialize_errc::ok)
return err;
}
// Validity check. deserialize_binary_ymd already does it for date
if (hours > max_hour || minutes > max_min || seconds > max_sec || micros > max_micro)
{
return deserialize_errc::protocol_value_error;
}
// Compose the final datetime
boost::mysql::datetime dt(d.year(), d.month(), d.day(), hours, minutes, seconds, micros);
output = field_view(dt);
return deserialize_errc::ok;
}
BOOST_MYSQL_STATIC_OR_INLINE
deserialize_errc deserialize_binary_field_time(deserialization_context& ctx, field_view& output) noexcept
{
using namespace boost::mysql::detail;
using namespace boost::mysql::detail::binc;
// Deserialize length
std::uint8_t length;
auto err = deserialize(ctx, length);
if (err != deserialize_errc::ok)
return err;
// If the TIME contains no value for these fields, they are zero
std::uint8_t is_negative = 0;
std::uint32_t num_days = 0;
std::uint8_t hours = 0;
std::uint8_t minutes = 0;
std::uint8_t seconds = 0;
std::uint32_t microseconds = 0;
// Sign, days, hours, minutes, seconds
if (length >= time_dhms_sz)
{
err = deserialize(ctx, is_negative, num_days, hours, minutes, seconds);
if (err != deserialize_errc::ok)
return err;
}
// Microseconds
if (length >= time_dhmsu_sz)
{
err = deserialize(ctx, microseconds);
if (err != deserialize_errc::ok)
return err;
}
// Range check
if (num_days > time_max_days || hours > max_hour || minutes > max_min || seconds > max_sec ||
microseconds > max_micro)
{
return deserialize_errc::protocol_value_error;
}
// Compose the final time
output = field_view(boost::mysql::time(
(is_negative ? -1 : 1) *
(boost::mysql::days(num_days) + std::chrono::hours(hours) + std::chrono::minutes(minutes) +
std::chrono::seconds(seconds) + std::chrono::microseconds(microseconds))
));
return deserialize_errc::ok;
}
} // namespace detail
} // namespace mysql
} // namespace boost
boost::mysql::detail::deserialize_errc boost::mysql::detail::deserialize_binary_field(
deserialization_context& ctx,
const metadata& meta,
field_view& output
)
{
switch (meta.type())
{
case column_type::tinyint:
return deserialize_binary_field_int<std::uint8_t, std::int8_t>(meta, ctx, output);
case column_type::smallint:
case column_type::year:
return deserialize_binary_field_int<std::uint16_t, std::int16_t>(meta, ctx, output);
case column_type::mediumint:
case column_type::int_:
return deserialize_binary_field_int<std::uint32_t, std::int32_t>(meta, ctx, output);
case column_type::bigint:
return deserialize_binary_field_int<std::uint64_t, std::int64_t>(meta, ctx, output);
case column_type::bit: return deserialize_binary_field_bit(ctx, output);
case column_type::float_: return deserialize_binary_field_float<float>(ctx, output);
case column_type::double_: return deserialize_binary_field_float<double>(ctx, output);
case column_type::timestamp:
case column_type::datetime: return deserialize_binary_field_datetime(ctx, output);
case column_type::date: return deserialize_binary_field_date(ctx, output);
case column_type::time: return deserialize_binary_field_time(ctx, output);
// True string types
case column_type::char_:
case column_type::varchar:
case column_type::text:
case column_type::enum_:
case column_type::set:
case column_type::decimal:
case column_type::json: return deserialize_binary_field_string(ctx, output, false);
// Blobs and anything else
case column_type::binary:
case column_type::varbinary:
case column_type::blob:
case column_type::geometry:
default: return deserialize_binary_field_string(ctx, output, true);
}
}
#endif
@@ -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_IMPL_INTERNAL_PROTOCOL_DESERIALIZE_TEXT_FIELD_HPP
#define BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_DESERIALIZE_TEXT_FIELD_HPP
#include <boost/mysql/field_view.hpp>
#include <boost/mysql/metadata.hpp>
#include <boost/mysql/detail/config.hpp>
#include <boost/mysql/impl/internal/protocol/serialization.hpp>
namespace boost {
namespace mysql {
namespace detail {
BOOST_MYSQL_DECL
deserialize_errc deserialize_text_field(string_view from, const metadata& meta, field_view& output);
} // namespace detail
} // namespace mysql
} // namespace boost
#ifdef BOOST_MYSQL_HEADER_ONLY
#include <boost/mysql/impl/internal/protocol/deserialize_text_field.ipp>
#endif
#endif
@@ -0,0 +1,336 @@
//
// 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_IMPL_INTERNAL_PROTOCOL_DESERIALIZE_TEXT_FIELD_IPP
#define BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_DESERIALIZE_TEXT_FIELD_IPP
#pragma once
#include <boost/mysql/blob_view.hpp>
#include <boost/mysql/datetime.hpp>
#include <boost/mysql/field_view.hpp>
#include <boost/mysql/metadata.hpp>
#include <boost/mysql/string_view.hpp>
#include <boost/mysql/detail/config.hpp>
#include <boost/mysql/detail/datetime.hpp>
#include <boost/mysql/impl/internal/protocol/bit_deserialization.hpp>
#include <boost/mysql/impl/internal/protocol/constants.hpp>
#include <boost/mysql/impl/internal/protocol/deserialize_text_field.hpp>
#include <boost/mysql/impl/internal/protocol/serialization.hpp>
#include <boost/assert.hpp>
#include <boost/lexical_cast/try_lexical_convert.hpp>
#include <cmath>
#include <cstddef>
#include <cstdlib>
#include <type_traits>
namespace boost {
namespace mysql {
namespace detail {
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable : 4996) // MSVC doesn't like my sscanf's
#endif
// Constants
BOOST_MYSQL_STATIC_IF_COMPILED constexpr unsigned max_decimals = 6u;
namespace textc {
BOOST_MYSQL_STATIC_IF_COMPILED constexpr std::size_t year_sz = 4;
BOOST_MYSQL_STATIC_IF_COMPILED constexpr std::size_t month_sz = 2;
BOOST_MYSQL_STATIC_IF_COMPILED constexpr std::size_t day_sz = 2;
BOOST_MYSQL_STATIC_IF_COMPILED constexpr std::size_t hours_min_sz = 2; // in TIME, it may be longer
BOOST_MYSQL_STATIC_IF_COMPILED constexpr std::size_t mins_sz = 2;
BOOST_MYSQL_STATIC_IF_COMPILED constexpr std::size_t secs_sz = 2;
BOOST_MYSQL_STATIC_IF_COMPILED constexpr std::size_t date_sz = year_sz + month_sz + day_sz + 2; // delimiters
BOOST_MYSQL_STATIC_IF_COMPILED constexpr std::size_t time_min_sz = hours_min_sz + mins_sz + secs_sz +
2; // delimiters
BOOST_MYSQL_STATIC_IF_COMPILED constexpr std::size_t time_max_sz = time_min_sz + max_decimals +
3; // sign, period, hour extra character
BOOST_MYSQL_STATIC_IF_COMPILED constexpr std::size_t datetime_min_sz = date_sz + time_min_sz +
1; // delimiter
BOOST_MYSQL_STATIC_IF_COMPILED constexpr std::size_t datetime_max_sz = datetime_min_sz + max_decimals +
1; // period
BOOST_MYSQL_STATIC_IF_COMPILED constexpr unsigned time_max_hour = 838;
} // namespace textc
// Integers
template <class T>
BOOST_MYSQL_STATIC_OR_INLINE deserialize_errc
deserialize_text_value_int_impl(string_view from, field_view& to) noexcept
{
T v;
bool ok = boost::conversion::try_lexical_convert(from.data(), from.size(), v);
if (!ok)
return deserialize_errc::protocol_value_error;
to = field_view(v);
return deserialize_errc::ok;
}
BOOST_MYSQL_STATIC_OR_INLINE deserialize_errc
deserialize_text_value_int(string_view from, field_view& to, const metadata& meta) noexcept
{
return meta.is_unsigned() ? deserialize_text_value_int_impl<std::uint64_t>(from, to)
: deserialize_text_value_int_impl<std::int64_t>(from, to);
}
// Floating points
template <class T>
BOOST_MYSQL_STATIC_OR_INLINE deserialize_errc
deserialize_text_value_float(string_view from, field_view& to) noexcept
{
T val;
bool ok = boost::conversion::try_lexical_convert(from.data(), from.size(), val);
if (!ok || std::isnan(val) || std::isinf(val)) // SQL std forbids these values
return deserialize_errc::protocol_value_error;
to = field_view(val);
return deserialize_errc::ok;
}
// Strings
BOOST_MYSQL_STATIC_OR_INLINE deserialize_errc
deserialize_text_value_string(string_view from, field_view& to) noexcept
{
to = field_view(from);
return deserialize_errc::ok;
}
BOOST_MYSQL_STATIC_OR_INLINE deserialize_errc
deserialize_text_value_blob(string_view from, field_view& to) noexcept
{
to = field_view(to_span(from));
return deserialize_errc::ok;
}
// Date/time types
BOOST_MYSQL_STATIC_OR_INLINE unsigned sanitize_decimals(unsigned decimals) noexcept
{
return (std::min)(decimals, max_decimals);
}
// Computes the meaning of the parsed microsecond number, taking into
// account decimals (85 with 2 decimals means 850000us)
BOOST_MYSQL_STATIC_OR_INLINE unsigned compute_micros(unsigned parsed_micros, unsigned decimals) noexcept
{
return parsed_micros * static_cast<unsigned>(std::pow(10, max_decimals - decimals));
}
BOOST_MYSQL_STATIC_OR_INLINE deserialize_errc deserialize_text_ymd(string_view from, date& to)
{
using namespace textc;
// Size check
if (from.size() != date_sz)
return deserialize_errc::protocol_value_error;
// Copy to a NULL-terminated buffer
char buffer[date_sz + 1]{};
std::memcpy(buffer, from.data(), from.size());
// Parse individual components
unsigned year, month, day;
char extra_char;
int parsed = sscanf(buffer, "%4u-%2u-%2u%c", &year, &month, &day, &extra_char);
if (parsed != 3)
return deserialize_errc::protocol_value_error;
// Range check for individual components. MySQL doesn't allow invidiual components
// to be out of range, although they may be zero or representing an invalid date
if (year > max_year || month > max_month || day > max_day)
return deserialize_errc::protocol_value_error;
to = date(
static_cast<std::uint16_t>(year),
static_cast<std::uint8_t>(month),
static_cast<std::uint8_t>(day)
);
return deserialize_errc::ok;
}
BOOST_MYSQL_STATIC_OR_INLINE deserialize_errc
deserialize_text_value_date(string_view from, field_view& to) noexcept
{
date d;
auto err = deserialize_text_ymd(from, d);
if (err != deserialize_errc::ok)
return err;
to = field_view(d);
return deserialize_errc::ok;
}
BOOST_MYSQL_STATIC_OR_INLINE deserialize_errc
deserialize_text_value_datetime(string_view from, field_view& to, const metadata& meta) noexcept
{
using namespace textc;
// Sanitize decimals
unsigned decimals = sanitize_decimals(meta.decimals());
// Length check
std::size_t expected_size = datetime_min_sz + (decimals ? decimals + 1 : 0);
if (from.size() != expected_size)
return deserialize_errc::protocol_value_error;
// Deserialize date part
date d;
auto err = deserialize_text_ymd(from.substr(0, date_sz), d);
if (err != deserialize_errc::ok)
return err;
// Copy to NULL-terminated buffer
constexpr std::size_t datetime_time_first = date_sz + 1; // date + space
char buffer[datetime_max_sz - datetime_time_first + 1]{};
std::memcpy(buffer, from.data() + datetime_time_first, from.size() - datetime_time_first);
// Parse
unsigned hours, minutes, seconds;
unsigned micros = 0;
char extra_char;
if (decimals)
{
int parsed = sscanf(buffer, "%2u:%2u:%2u.%6u%c", &hours, &minutes, &seconds, &micros, &extra_char);
if (parsed != 4)
return deserialize_errc::protocol_value_error;
micros = compute_micros(micros, decimals);
}
else
{
int parsed = sscanf(buffer, "%2u:%2u:%2u%c", &hours, &minutes, &seconds, &extra_char);
if (parsed != 3)
return deserialize_errc::protocol_value_error;
}
// Validity check. Although MySQL allows invalid and zero datetimes, it doesn't allow
// individual components to be out of range.
if (hours > max_hour || minutes > max_min || seconds > max_sec || micros > max_micro)
{
return deserialize_errc::protocol_value_error;
}
datetime dt(
d.year(),
d.month(),
d.day(),
static_cast<std::uint8_t>(hours),
static_cast<std::uint8_t>(minutes),
static_cast<std::uint8_t>(seconds),
static_cast<std::uint32_t>(micros)
);
to = field_view(dt);
return deserialize_errc::ok;
}
BOOST_MYSQL_STATIC_OR_INLINE deserialize_errc
deserialize_text_value_time(string_view from, field_view& to, const metadata& meta) noexcept
{
using namespace textc;
// Sanitize decimals
unsigned decimals = sanitize_decimals(meta.decimals());
// size check
std::size_t actual_min_size = time_min_sz + (decimals ? decimals + 1 : 0);
std::size_t actual_max_size = actual_min_size + 1 + 1; // hour extra character and sign
BOOST_ASSERT(actual_max_size <= time_max_sz);
if (from.size() < actual_min_size || from.size() > actual_max_size)
return deserialize_errc::protocol_value_error;
// Copy to NULL-terminated buffer
char buffer[time_max_sz + 1]{};
memcpy(buffer, from.data(), from.size());
// Sign
bool is_negative = from[0] == '-';
const char* first = is_negative ? buffer + 1 : buffer;
// Parse it
unsigned hours, minutes, seconds;
unsigned micros = 0;
char extra_char;
if (decimals)
{
int parsed = sscanf(first, "%3u:%2u:%2u.%6u%c", &hours, &minutes, &seconds, &micros, &extra_char);
if (parsed != 4)
return deserialize_errc::protocol_value_error;
micros = compute_micros(micros, decimals);
}
else
{
int parsed = sscanf(first, "%3u:%2u:%2u%c", &hours, &minutes, &seconds, &extra_char);
if (parsed != 3)
return deserialize_errc::protocol_value_error;
}
// Range check
if (hours > time_max_hour || minutes > max_min || seconds > max_sec || micros > max_micro)
{
return deserialize_errc::protocol_value_error;
}
// Sum it
auto res = std::chrono::hours(hours) + std::chrono::minutes(minutes) + std::chrono::seconds(seconds) +
std::chrono::microseconds(micros);
if (is_negative)
{
res = -res;
}
// Done
to = field_view(res);
return deserialize_errc::ok;
}
} // namespace detail
} // namespace mysql
} // namespace boost
boost::mysql::detail::deserialize_errc boost::mysql::detail::deserialize_text_field(
string_view from,
const metadata& meta,
field_view& output
)
{
switch (meta.type())
{
case column_type::tinyint:
case column_type::smallint:
case column_type::mediumint:
case column_type::int_:
case column_type::bigint:
case column_type::year: return deserialize_text_value_int(from, output, meta);
case column_type::bit: return deserialize_bit(from, output);
case column_type::float_: return deserialize_text_value_float<float>(from, output);
case column_type::double_: return deserialize_text_value_float<double>(from, output);
case column_type::timestamp:
case column_type::datetime: return deserialize_text_value_datetime(from, output, meta);
case column_type::date: return deserialize_text_value_date(from, output);
case column_type::time: return deserialize_text_value_time(from, output, meta);
// True string types
case column_type::char_:
case column_type::varchar:
case column_type::text:
case column_type::enum_:
case column_type::set:
case column_type::decimal:
case column_type::json: return deserialize_text_value_string(from, output);
// Blobs and anything else
case column_type::binary:
case column_type::varbinary:
case column_type::blob:
case column_type::geometry:
default: return deserialize_text_value_blob(from, output);
}
}
#endif
@@ -0,0 +1,54 @@
//
// 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_IMPL_INTERNAL_PROTOCOL_NULL_BITMAP_TRAITS_HPP
#define BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_NULL_BITMAP_TRAITS_HPP
#include <boost/assert.hpp>
#include <cstddef>
#include <cstdint>
namespace boost {
namespace mysql {
namespace detail {
class null_bitmap_traits
{
std::size_t offset_;
std::size_t num_fields_;
constexpr std::size_t byte_pos(std::size_t field_pos) const noexcept { return (field_pos + offset_) / 8; }
constexpr std::size_t bit_pos(std::size_t field_pos) const noexcept { return (field_pos + offset_) % 8; }
public:
constexpr null_bitmap_traits(std::size_t offset, std::size_t num_fields) noexcept
: offset_(offset), num_fields_{num_fields} {};
constexpr std::size_t offset() const noexcept { return offset_; }
constexpr std::size_t num_fields() const noexcept { return num_fields_; }
constexpr std::size_t byte_count() const noexcept { return (num_fields_ + 7 + offset_) / 8; }
bool is_null(const std::uint8_t* null_bitmap_begin, std::size_t field_pos) const noexcept
{
BOOST_ASSERT(field_pos < num_fields_);
return null_bitmap_begin[byte_pos(field_pos)] & (1 << bit_pos(field_pos));
}
void set_null(std::uint8_t* null_bitmap_begin, std::size_t field_pos) const noexcept
{
BOOST_ASSERT(field_pos < num_fields_);
null_bitmap_begin[byte_pos(field_pos)] |= (1 << bit_pos(field_pos));
}
};
constexpr std::size_t stmt_execute_null_bitmap_offset = 0;
constexpr std::size_t binary_row_null_bitmap_offset = 2;
} // namespace detail
} // namespace mysql
} // namespace boost
#endif /* INCLUDE_NULL_BITMAP_HPP_ */
+341
View File
@@ -0,0 +1,341 @@
//
// 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_IMPL_INTERNAL_PROTOCOL_PROTOCOL_HPP
#define BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_PROTOCOL_HPP
#include <boost/mysql/column_type.hpp>
#include <boost/mysql/diagnostics.hpp>
#include <boost/mysql/error_code.hpp>
#include <boost/mysql/field_view.hpp>
#include <boost/mysql/metadata_collection_view.hpp>
#include <boost/mysql/string_view.hpp>
#include <boost/mysql/detail/coldef_view.hpp>
#include <boost/mysql/detail/config.hpp>
#include <boost/mysql/detail/ok_view.hpp>
#include <boost/mysql/detail/resultset_encoding.hpp>
#include <boost/mysql/impl/internal/protocol/capabilities.hpp>
#include <boost/mysql/impl/internal/protocol/constants.hpp>
#include <boost/mysql/impl/internal/protocol/db_flavor.hpp>
#include <boost/mysql/impl/internal/protocol/static_buffer.hpp>
#include <boost/config.hpp>
#include <boost/core/span.hpp>
#include <cstddef>
#include <cstdint>
#include <type_traits>
namespace boost {
namespace mysql {
namespace detail {
// Frame header
constexpr std::size_t frame_header_size = 4;
struct frame_header
{
std::uint32_t size;
std::uint8_t sequence_number;
};
BOOST_MYSQL_DECL
void serialize_frame_header(frame_header, span<std::uint8_t, frame_header_size> buffer) noexcept;
BOOST_MYSQL_DECL
frame_header deserialize_frame_header(span<const std::uint8_t, frame_header_size> buffer) noexcept;
// OK packets (views because strings are non-owning)
BOOST_MYSQL_DECL
error_code deserialize_ok_packet(span<const std::uint8_t> msg, ok_view& output) noexcept; // for testing
// Error packets (exposed for testing)
struct err_view
{
std::uint16_t error_code;
string_view error_message;
};
BOOST_ATTRIBUTE_NODISCARD BOOST_MYSQL_DECL error_code
deserialize_error_packet(span<const std::uint8_t> message, err_view& pack) noexcept;
BOOST_ATTRIBUTE_NODISCARD BOOST_MYSQL_DECL error_code
process_error_packet(span<const std::uint8_t> message, db_flavor flavor, diagnostics& diag);
// Column definition
BOOST_ATTRIBUTE_NODISCARD BOOST_MYSQL_DECL error_code
deserialize_column_definition(span<const std::uint8_t> input, coldef_view& output) noexcept;
// Quit
struct quit_command
{
BOOST_MYSQL_DECL std::size_t get_size() const noexcept;
BOOST_MYSQL_DECL void serialize(span<std::uint8_t> buffer) const noexcept;
};
// Ping
struct ping_command
{
BOOST_MYSQL_DECL std::size_t get_size() const noexcept;
BOOST_MYSQL_DECL void serialize(span<std::uint8_t> buffer) const noexcept;
};
// Reset connection
struct reset_connection_command
{
BOOST_MYSQL_DECL std::size_t get_size() const noexcept;
BOOST_MYSQL_DECL void serialize(span<std::uint8_t> buffer) const noexcept;
};
// Deserializes a response that may be an OK or an error packet.
// Applicable for ping and reset connection
BOOST_ATTRIBUTE_NODISCARD BOOST_MYSQL_DECL error_code
deserialize_ok_response(span<const std::uint8_t> message, db_flavor flavor, diagnostics& diag);
// Query
struct query_command
{
string_view query;
BOOST_MYSQL_DECL std::size_t get_size() const noexcept;
BOOST_MYSQL_DECL void serialize(span<std::uint8_t> buffer) const noexcept;
};
// Prepare statement
struct prepare_stmt_command
{
string_view stmt;
BOOST_MYSQL_DECL std::size_t get_size() const noexcept;
BOOST_MYSQL_DECL void serialize(span<std::uint8_t> buffer) const noexcept;
};
struct prepare_stmt_response
{
std::uint32_t id;
std::uint16_t num_columns;
std::uint16_t num_params;
};
BOOST_ATTRIBUTE_NODISCARD BOOST_MYSQL_DECL error_code deserialize_prepare_stmt_response_impl(
span<const std::uint8_t> message,
prepare_stmt_response& output
) noexcept; // exposed for testing, doesn't take header into account
BOOST_ATTRIBUTE_NODISCARD BOOST_MYSQL_DECL error_code deserialize_prepare_stmt_response(
span<const std::uint8_t> message,
db_flavor flavor,
prepare_stmt_response& output,
diagnostics& diag
);
// Execute statement
struct execute_stmt_command
{
std::uint32_t statement_id;
span<const field_view> params;
BOOST_MYSQL_DECL std::size_t get_size() const noexcept;
BOOST_MYSQL_DECL void serialize(span<std::uint8_t> buffer) const noexcept;
};
// Close statement
struct close_stmt_command
{
std::uint32_t statement_id{};
constexpr close_stmt_command() = default;
constexpr close_stmt_command(std::uint32_t statement_id) noexcept : statement_id(statement_id) {}
BOOST_MYSQL_DECL std::size_t get_size() const noexcept;
BOOST_MYSQL_DECL void serialize(span<std::uint8_t> buffer) const noexcept;
};
// Execution messages
static_assert(std::is_trivially_destructible<error_code>::value, "");
struct execute_response
{
enum class type_t
{
num_fields,
ok_packet,
error
} type;
union data_t
{
std::size_t num_fields;
ok_view ok_pack;
error_code err;
data_t(size_t v) noexcept : num_fields(v) {}
data_t(const ok_view& v) noexcept : ok_pack(v) {}
data_t(error_code v) noexcept : err(v) {}
} data;
execute_response(std::size_t v) noexcept : type(type_t::num_fields), data(v) {}
execute_response(const ok_view& v) noexcept : type(type_t::ok_packet), data(v) {}
execute_response(error_code v) noexcept : type(type_t::error), data(v) {}
};
BOOST_MYSQL_DECL
execute_response deserialize_execute_response(
span<const std::uint8_t> msg,
db_flavor flavor,
diagnostics& diag
) noexcept;
struct row_message
{
enum class type_t
{
row,
ok_packet,
error
} type;
union data_t
{
span<const std::uint8_t> row;
ok_view ok_pack;
error_code err;
data_t(span<const std::uint8_t> row) noexcept : row(row) {}
data_t(const ok_view& ok_pack) noexcept : ok_pack(ok_pack) {}
data_t(error_code err) noexcept : err(err) {}
} data;
row_message(span<const std::uint8_t> row) noexcept : type(type_t::row), data(row) {}
row_message(const ok_view& ok_pack) noexcept : type(type_t::ok_packet), data(ok_pack) {}
row_message(error_code v) noexcept : type(type_t::error), data(v) {}
};
BOOST_MYSQL_DECL
row_message deserialize_row_message(span<const std::uint8_t> msg, db_flavor flavor, diagnostics& diag);
BOOST_MYSQL_DECL
error_code deserialize_row(
resultset_encoding encoding,
span<const std::uint8_t> message,
metadata_collection_view meta,
span<field_view> output // Should point to meta.size() field_view objects
);
// Server hello
struct server_hello
{
using auth_buffer_type = static_buffer<8 + 0xff>;
db_flavor server;
auth_buffer_type auth_plugin_data;
capabilities server_capabilities{};
string_view auth_plugin_name;
};
BOOST_ATTRIBUTE_NODISCARD BOOST_MYSQL_DECL error_code deserialize_server_hello_impl(
span<const std::uint8_t> msg,
server_hello& output
); // exposed for testing, doesn't take message header into account
BOOST_ATTRIBUTE_NODISCARD BOOST_MYSQL_DECL error_code
deserialize_server_hello(span<const std::uint8_t> msg, server_hello& output, diagnostics& diag);
// Login & ssl requests
struct login_request
{
capabilities negotiated_capabilities; // capabilities
std::uint32_t max_packet_size;
std::uint32_t collation_id;
string_view username;
span<const std::uint8_t> auth_response;
string_view database;
string_view auth_plugin_name;
BOOST_MYSQL_DECL std::size_t get_size() const noexcept;
BOOST_MYSQL_DECL void serialize(span<std::uint8_t> buffer) const noexcept;
};
struct ssl_request
{
capabilities negotiated_capabilities;
std::uint32_t max_packet_size;
std::uint32_t collation_id;
BOOST_MYSQL_DECL std::size_t get_size() const noexcept;
BOOST_MYSQL_DECL void serialize(span<std::uint8_t> buffer) const noexcept;
};
// Auth switch
struct auth_switch
{
string_view plugin_name;
span<const std::uint8_t> auth_data;
};
BOOST_ATTRIBUTE_NODISCARD BOOST_MYSQL_DECL error_code deserialize_auth_switch(
span<const std::uint8_t> msg,
auth_switch& output
) noexcept; // exposed for testing
struct handhake_server_response
{
struct ok_follows_t
{
};
enum class type_t
{
ok,
error,
ok_follows,
auth_switch,
auth_more_data
} type;
union data_t
{
ok_view ok;
error_code err;
ok_follows_t ok_follows;
auth_switch auth_sw;
span<const std::uint8_t> more_data;
data_t(const ok_view& ok) noexcept : ok(ok) {}
data_t(error_code err) noexcept : err(err) {}
data_t(ok_follows_t) noexcept : ok_follows({}) {}
data_t(auth_switch msg) noexcept : auth_sw(msg) {}
data_t(span<const std::uint8_t> more_data) noexcept : more_data(more_data) {}
} data;
handhake_server_response(const ok_view& ok) noexcept : type(type_t::ok), data(ok) {}
handhake_server_response(error_code err) noexcept : type(type_t::error), data(err) {}
handhake_server_response(ok_follows_t) noexcept : type(type_t::ok_follows), data(ok_follows_t{}) {}
handhake_server_response(auth_switch auth_switch) noexcept : type(type_t::auth_switch), data(auth_switch)
{
}
handhake_server_response(span<const std::uint8_t> more_data) noexcept
: type(type_t::auth_more_data), data(more_data)
{
}
};
BOOST_MYSQL_DECL
handhake_server_response deserialize_handshake_server_response(
span<const std::uint8_t> buff,
db_flavor flavor,
diagnostics& diag
);
struct auth_switch_response
{
span<const std::uint8_t> auth_plugin_data;
BOOST_MYSQL_DECL std::size_t get_size() const noexcept;
BOOST_MYSQL_DECL void serialize(span<std::uint8_t> buffer) const noexcept;
};
} // namespace detail
} // namespace mysql
} // namespace boost
#ifdef BOOST_MYSQL_HEADER_ONLY
#include <boost/mysql/impl/internal/protocol/protocol.ipp>
#endif
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,67 @@
//
// 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_IMPL_INTERNAL_PROTOCOL_PROTOCOL_FIELD_TYPE_HPP
#define BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_PROTOCOL_FIELD_TYPE_HPP
#include <boost/mysql/column_type.hpp>
#include <boost/mysql/detail/config.hpp>
#include <cstdint>
namespace boost {
namespace mysql {
namespace detail {
enum class protocol_field_type : std::uint8_t
{
decimal = 0x00, // Apparently not sent
tiny = 0x01, // TINYINT
short_ = 0x02, // SMALLINT
long_ = 0x03, // INT
float_ = 0x04, // FLOAT
double_ = 0x05, // DOUBLE
null = 0x06, // Apparently not sent
timestamp = 0x07, // TIMESTAMP
longlong = 0x08, // BIGINT
int24 = 0x09, // MEDIUMINT
date = 0x0a, // DATE
time = 0x0b, // TIME
datetime = 0x0c, // DATETIME
year = 0x0d, // YEAR
varchar = 0x0f, // Apparently not sent
bit = 0x10, // BIT
json = 0xf5, // JSON
newdecimal = 0xf6, // DECIMAL
enum_ = 0xf7, // Apparently not sent
set = 0xf8, // Apperently not sent
tiny_blob = 0xf9, // Apparently not sent
medium_blob = 0xfa, // Apparently not sent
long_blob = 0xfb, // Apparently not sent
blob = 0xfc, // Used for all TEXT and BLOB types
var_string = 0xfd, // Used for VARCHAR and VARBINARY
string = 0xfe, // Used for CHAR and BINARY, ENUM (enum flag set), SET (set flag set)
geometry = 0xff // GEOMETRY
};
BOOST_MYSQL_DECL
column_type compute_column_type(
protocol_field_type protocol_type,
std::uint16_t flags,
std::uint16_t collation
) noexcept;
} // namespace detail
} // namespace mysql
} // namespace boost
#ifdef BOOST_MYSQL_HEADER_ONLY
#include <boost/mysql/impl/internal/protocol/protocol_field_type.ipp>
#endif
#endif
@@ -0,0 +1,94 @@
//
// 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_IMPL_INTERNAL_PROTOCOL_PROTOCOL_FIELD_TYPE_IPP
#define BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_PROTOCOL_FIELD_TYPE_IPP
#pragma once
#include <boost/mysql/detail/config.hpp>
#include <boost/mysql/detail/flags.hpp>
#include <boost/mysql/impl/internal/protocol/constants.hpp>
#include <boost/mysql/impl/internal/protocol/protocol_field_type.hpp>
namespace boost {
namespace mysql {
namespace detail {
BOOST_MYSQL_STATIC_OR_INLINE
column_type compute_field_type_string(std::uint16_t flags, std::uint16_t collation) noexcept
{
if (flags & column_flags::set)
return column_type::set;
else if (flags & column_flags::enum_)
return column_type::enum_;
else if (collation == binary_collation)
return column_type::binary;
else
return column_type::char_;
}
BOOST_MYSQL_STATIC_OR_INLINE
column_type compute_field_type_var_string(std::uint16_t collation) noexcept
{
return collation == binary_collation ? column_type::varbinary : column_type::varchar;
}
BOOST_MYSQL_STATIC_OR_INLINE
column_type compute_field_type_blob(std::uint16_t collation) noexcept
{
return collation == binary_collation ? column_type::blob : column_type::text;
}
} // namespace detail
} // namespace mysql
} // namespace boost
boost::mysql::column_type boost::mysql::detail::compute_column_type(
protocol_field_type protocol_type,
std::uint16_t flags,
std::uint16_t collation
) noexcept
{
// Some protocol_field_types seem to not be sent by the server. We've found instances
// where some servers, with certain SQL statements, send some of the "apparently not sent"
// types (e.g. MariaDB was sending medium_blob only if you SELECT TEXT variables - but not with TEXT
// columns). So we've taken a defensive approach here
switch (protocol_type)
{
case protocol_field_type::decimal:
case protocol_field_type::newdecimal: return column_type::decimal;
case protocol_field_type::geometry: return column_type::geometry;
case protocol_field_type::tiny: return column_type::tinyint;
case protocol_field_type::short_: return column_type::smallint;
case protocol_field_type::int24: return column_type::mediumint;
case protocol_field_type::long_: return column_type::int_;
case protocol_field_type::longlong: return column_type::bigint;
case protocol_field_type::float_: return column_type::float_;
case protocol_field_type::double_: return column_type::double_;
case protocol_field_type::bit: return column_type::bit;
case protocol_field_type::date: return column_type::date;
case protocol_field_type::datetime: return column_type::datetime;
case protocol_field_type::timestamp: return column_type::timestamp;
case protocol_field_type::time: return column_type::time;
case protocol_field_type::year: return column_type::year;
case protocol_field_type::json: return column_type::json;
case protocol_field_type::enum_: return column_type::enum_; // in theory not set
case protocol_field_type::set: return column_type::set; // in theory not set
case protocol_field_type::string: return compute_field_type_string(flags, collation);
case protocol_field_type::varchar: // in theory not sent
case protocol_field_type::var_string: return compute_field_type_var_string(collation);
case protocol_field_type::tiny_blob: // in theory not sent
case protocol_field_type::medium_blob: // in theory not sent
case protocol_field_type::long_blob: // in theory not sent
case protocol_field_type::blob: return compute_field_type_blob(collation);
default: return column_type::unknown;
}
}
#endif
+387
View File
@@ -0,0 +1,387 @@
//
// 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_IMPL_INTERNAL_PROTOCOL_SERIALIZATION_HPP
#define BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_SERIALIZATION_HPP
#include <boost/mysql/client_errc.hpp>
#include <boost/mysql/error_code.hpp>
#include <boost/mysql/field_view.hpp>
#include <boost/mysql/string_view.hpp>
#include <boost/mysql/impl/internal/protocol/basic_types.hpp>
#include <boost/mysql/impl/internal/protocol/capabilities.hpp>
#include <boost/mysql/impl/internal/protocol/protocol_field_type.hpp>
#include <boost/assert.hpp>
#include <boost/core/span.hpp>
#include <boost/endian/conversion.hpp>
#include <boost/endian/detail/endian_load.hpp>
#include <boost/endian/detail/endian_store.hpp>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <type_traits>
namespace boost {
namespace mysql {
namespace detail {
// We operate with this enum directly in the deserialization routines for efficiency, then transform it to an
// actual error code
enum class deserialize_errc
{
ok = 0,
incomplete_message = 1,
protocol_value_error,
server_unsupported
};
inline error_code to_error_code(deserialize_errc v) noexcept
{
switch (v)
{
case deserialize_errc::ok: return error_code();
case deserialize_errc::incomplete_message: return error_code(client_errc::incomplete_message);
case deserialize_errc::protocol_value_error: return error_code(client_errc::protocol_value_error);
case deserialize_errc::server_unsupported: return error_code(client_errc::server_unsupported);
default: BOOST_ASSERT(false); return error_code(); // avoid warnings
}
}
class serialization_context
{
std::uint8_t* first_;
public:
explicit serialization_context(std::uint8_t* first) noexcept : first_(first) {}
std::uint8_t* first() const noexcept { return first_; }
void advance(std::size_t size) noexcept { first_ += size; }
void write(const void* buffer, std::size_t size) noexcept
{
if (size)
{
BOOST_ASSERT(buffer != nullptr);
std::memcpy(first_, buffer, size);
advance(size);
}
}
void write(std::uint8_t elm) noexcept
{
*first_ = elm;
++first_;
}
};
class deserialization_context
{
const std::uint8_t* first_;
const std::uint8_t* last_;
public:
deserialization_context(span<const std::uint8_t> data) noexcept
: deserialization_context(data.data(), data.size())
{
}
deserialization_context(const std::uint8_t* first, std::size_t size) noexcept
: first_(first), last_(first + size){};
const std::uint8_t* first() const noexcept { return first_; }
const std::uint8_t* last() const noexcept { return last_; }
void advance(std::size_t sz) noexcept
{
first_ += sz;
BOOST_ASSERT(last_ >= first_);
}
void rewind(std::size_t sz) noexcept { first_ -= sz; }
std::size_t size() const noexcept { return last_ - first_; }
bool empty() const noexcept { return last_ == first_; }
bool enough_size(std::size_t required_size) const noexcept { return size() >= required_size; }
deserialize_errc copy(void* to, std::size_t sz) noexcept
{
if (!enough_size(sz))
return deserialize_errc::incomplete_message;
memcpy(to, first_, sz);
advance(sz);
return deserialize_errc::ok;
}
string_view get_string(std::size_t sz) const noexcept
{
return string_view(reinterpret_cast<const char*>(first_), sz);
}
error_code check_extra_bytes() const noexcept
{
return empty() ? error_code() : error_code(client_errc::extra_bytes);
}
span<const std::uint8_t> to_span() const noexcept { return span<const std::uint8_t>(first_, size()); }
};
// integers
template <class T, class = typename std::enable_if<std::is_integral<T>::value>::type>
deserialize_errc deserialize(deserialization_context& ctx, T& output) noexcept
{
constexpr std::size_t sz = sizeof(T);
if (!ctx.enough_size(sz))
{
return deserialize_errc::incomplete_message;
}
output = endian::endian_load<T, sz, boost::endian::order::little>(ctx.first());
ctx.advance(sz);
return deserialize_errc::ok;
}
template <class T, class = typename std::enable_if<std::is_integral<T>::value>::type>
void serialize(serialization_context& ctx, T input) noexcept
{
endian::endian_store<T, sizeof(T), endian::order::little>(ctx.first(), input);
ctx.advance(sizeof(T));
}
template <class T, class = typename std::enable_if<std::is_integral<T>::value>::type>
constexpr std::size_t get_size(T) noexcept
{
return sizeof(T);
}
// int3
inline deserialize_errc deserialize(deserialization_context& ctx, int3& output) noexcept
{
if (!ctx.enough_size(3))
return deserialize_errc::incomplete_message;
output.value = endian::load_little_u24(ctx.first());
ctx.advance(3);
return deserialize_errc::ok;
}
inline void serialize(serialization_context& ctx, int3 input) noexcept
{
endian::store_little_u24(ctx.first(), input.value);
ctx.advance(3);
}
constexpr std::size_t get_size(int3) noexcept { return 3; }
// int_lenenc
inline deserialize_errc deserialize(deserialization_context& ctx, int_lenenc& output) noexcept
{
std::uint8_t first_byte = 0;
auto err = deserialize(ctx, first_byte);
if (err != deserialize_errc::ok)
{
return err;
}
if (first_byte == 0xFC)
{
std::uint16_t value = 0;
err = deserialize(ctx, value);
output.value = value;
}
else if (first_byte == 0xFD)
{
int3 value{};
err = deserialize(ctx, value);
output.value = value.value;
}
else if (first_byte == 0xFE)
{
std::uint64_t value = 0;
err = deserialize(ctx, value);
output.value = value;
}
else
{
err = deserialize_errc::ok;
output.value = first_byte;
}
return err;
}
inline void serialize(serialization_context& ctx, int_lenenc input) noexcept
{
if (input.value < 251)
{
serialize(ctx, static_cast<std::uint8_t>(input.value));
}
else if (input.value < 0x10000)
{
ctx.write(0xfc);
serialize(ctx, static_cast<std::uint16_t>(input.value));
}
else if (input.value < 0x1000000)
{
ctx.write(0xfd);
serialize(ctx, int3{static_cast<std::uint32_t>(input.value)});
}
else
{
ctx.write(0xfe);
serialize(ctx, static_cast<std::uint64_t>(input.value));
}
}
inline std::size_t get_size(int_lenenc input) noexcept
{
if (input.value < 251)
return 1;
else if (input.value < 0x10000)
return 3;
else if (input.value < 0x1000000)
return 4;
else
return 9;
}
// protocol_field_type
inline deserialize_errc deserialize(deserialization_context& ctx, protocol_field_type& output) noexcept
{
std::underlying_type<protocol_field_type>::type value = 0;
auto err = deserialize(ctx, value);
output = static_cast<protocol_field_type>(value);
return err;
}
inline void serialize(serialization_context& ctx, protocol_field_type input) noexcept
{
serialize(ctx, static_cast<std::underlying_type<protocol_field_type>::type>(input));
}
constexpr std::size_t get_size(protocol_field_type) noexcept { return sizeof(protocol_field_type); }
// string_fixed
template <std::size_t N>
deserialize_errc deserialize(deserialization_context& ctx, string_fixed<N>& output) noexcept
{
if (!ctx.enough_size(N))
return deserialize_errc::incomplete_message;
memcpy(output.value.data(), ctx.first(), N);
ctx.advance(N);
return deserialize_errc::ok;
}
template <std::size_t N>
void serialize(serialization_context& ctx, const string_fixed<N>& input) noexcept
{
ctx.write(input.value.data(), N);
}
template <std::size_t N>
constexpr std::size_t get_size(const string_fixed<N>&) noexcept
{
return N;
}
// string_null
inline deserialize_errc deserialize(deserialization_context& ctx, string_null& output) noexcept
{
auto string_end = std::find(ctx.first(), ctx.last(), 0);
if (string_end == ctx.last())
{
return deserialize_errc::incomplete_message;
}
std::size_t length = string_end - ctx.first();
output.value = ctx.get_string(length);
ctx.advance(length + 1); // skip the null terminator
return deserialize_errc::ok;
}
inline void serialize(serialization_context& ctx, string_null input) noexcept
{
ctx.write(input.value.data(), input.value.size());
ctx.write(0); // null terminator
}
inline std::size_t get_size(string_null input) noexcept { return input.value.size() + 1; }
// string_eof
inline deserialize_errc deserialize(deserialization_context& ctx, string_eof& output) noexcept
{
std::size_t size = ctx.size();
output.value = ctx.get_string(size);
ctx.advance(size);
return deserialize_errc::ok;
}
inline void serialize(serialization_context& ctx, string_eof input) noexcept
{
ctx.write(input.value.data(), input.value.size());
}
inline std::size_t get_size(string_eof input) noexcept { return input.value.size(); }
// string_lenenc
inline deserialize_errc deserialize(deserialization_context& ctx, string_lenenc& output) noexcept
{
int_lenenc length;
auto err = deserialize(ctx, length);
if (err != deserialize_errc::ok)
{
return err;
}
if (length.value > (std::numeric_limits<std::size_t>::max)())
{
return deserialize_errc::protocol_value_error;
}
auto len = static_cast<std::size_t>(length.value);
if (!ctx.enough_size(len))
{
return deserialize_errc::incomplete_message;
}
output.value = ctx.get_string(len);
ctx.advance(len);
return deserialize_errc::ok;
}
inline void serialize(serialization_context& ctx, string_lenenc input) noexcept
{
serialize(ctx, int_lenenc{input.value.size()});
ctx.write(input.value.data(), input.value.size());
}
inline std::size_t get_size(string_lenenc input) noexcept
{
return get_size(int_lenenc{input.value.size()}) + input.value.size();
}
// serialize, deserialize, and get size of multiple fields at the same time
template <class FirstType, class SecondType, class... Rest>
deserialize_errc deserialize(
deserialization_context& ctx,
FirstType& first,
SecondType& second,
Rest&... tail
) noexcept
{
deserialize_errc err = deserialize(ctx, first);
if (err == deserialize_errc::ok)
{
err = deserialize(ctx, second, tail...);
}
return err;
}
template <class FirstType, class SecondType, class... Rest>
void serialize(
serialization_context& ctx,
const FirstType& first,
const SecondType& second,
const Rest&... rest
) noexcept
{
serialize(ctx, first);
serialize(ctx, second, rest...);
}
template <class FirstType, class SecondType, class... Rest>
std::size_t get_size(const FirstType& first, const SecondType& second, const Rest&... rest) noexcept
{
return get_size(first) + get_size(second, rest...);
}
// helpers
inline string_view to_string(span<const std::uint8_t> v) noexcept
{
return string_view(reinterpret_cast<const char*>(v.data()), v.size());
}
inline span<const std::uint8_t> to_span(string_view v) noexcept
{
return span<const std::uint8_t>(reinterpret_cast<const std::uint8_t*>(v.data()), v.size());
}
} // namespace detail
} // namespace mysql
} // namespace boost
#endif
+46
View File
@@ -0,0 +1,46 @@
//
// 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_IMPL_INTERNAL_PROTOCOL_STATIC_BUFFER_HPP
#define BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_STATIC_BUFFER_HPP
// A very simplified variable-length buffer with fixed max-size
#include <boost/assert.hpp>
#include <boost/core/span.hpp>
#include <array>
#include <cstring>
namespace boost {
namespace mysql {
namespace detail {
template <std::size_t max_size>
class static_buffer
{
std::array<std::uint8_t, max_size> buffer_{};
std::size_t size_{};
public:
static_buffer() noexcept = default;
span<const std::uint8_t> to_span() const noexcept { return {buffer_.data(), size_}; }
void append(const void* data, std::size_t data_size) noexcept
{
std::size_t new_size = size_ + data_size;
BOOST_ASSERT(new_size <= max_size);
std::memcpy(buffer_.data() + size_, data, data_size);
size_ = new_size;
}
void clear() noexcept { size_ = 0; }
};
} // namespace detail
} // namespace mysql
} // namespace boost
#endif