mirror of
https://github.com/vdemydiuk/mtapi.git
synced 2026-08-05 23:17:52 +00:00
Added thirdparty: boost library
This commit is contained in:
+55
@@ -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
|
||||
+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_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
|
||||
+133
@@ -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
|
||||
+47
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
Vendored
Executable
+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_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_ */
|
||||
Vendored
Executable
+319
@@ -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
|
||||
Vendored
Executable
+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_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
|
||||
Vendored
Executable
+336
@@ -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, µs, &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, µs, &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
|
||||
+54
@@ -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
@@ -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
|
||||
+1092
File diff suppressed because it is too large
Load Diff
+67
@@ -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
|
||||
+94
@@ -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
@@ -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
@@ -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
|
||||
Reference in New Issue
Block a user