gnss-sim/3rdparty/boost/mysql/impl/internal/protocol/serialization.hpp

261 lines
7.2 KiB
C++

//
// Copyright (c) 2019-2024 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/field_view.hpp>
#include <boost/mysql/string_view.hpp>
#include <boost/mysql/impl/internal/protocol/capabilities.hpp>
#include <boost/mysql/impl/internal/protocol/frame_header.hpp>
#include <boost/mysql/impl/internal/protocol/impl/binary_protocol.hpp>
#include <boost/mysql/impl/internal/protocol/impl/null_bitmap.hpp>
#include <boost/mysql/impl/internal/protocol/impl/protocol_field_type.hpp>
#include <boost/mysql/impl/internal/protocol/impl/protocol_types.hpp>
#include <boost/mysql/impl/internal/protocol/impl/serialization_context.hpp>
#include <boost/assert.hpp>
#include <cstdint>
namespace boost {
namespace mysql {
namespace detail {
// quit
struct quit_command
{
void serialize(serialization_context& ctx) const { ctx.add(0x01); }
};
// ping
struct ping_command
{
void serialize(serialization_context& ctx) const { ctx.add(0x0e); }
};
// reset_connection
struct reset_connection_command
{
void serialize(serialization_context& ctx) const { ctx.add(0x1f); }
};
// query
struct query_command
{
string_view query;
void serialize(serialization_context& ctx) const
{
ctx.add(0x03);
string_eof{query}.serialize_checked(ctx);
}
};
// prepare_statement
struct prepare_stmt_command
{
string_view stmt;
void serialize(serialization_context& ctx) const
{
ctx.add(0x16);
string_eof{stmt}.serialize(ctx);
}
};
// execute statement
struct execute_stmt_command
{
std::uint32_t statement_id;
span<const field_view> params;
inline void serialize(serialization_context& ctx) const;
};
// close statement
struct close_stmt_command
{
std::uint32_t statement_id;
void serialize(serialization_context& ctx) const
{
ctx.add(0x19);
int4{statement_id}.serialize(ctx);
}
};
// Login request
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;
inline void serialize(serialization_context& ctx) const;
};
// SSL request
struct ssl_request
{
capabilities negotiated_capabilities;
std::uint32_t max_packet_size;
std::uint32_t collation_id;
inline void serialize(serialization_context& ctx) const;
};
// Auth switch response
struct auth_switch_response
{
span<const std::uint8_t> auth_plugin_data;
void serialize(serialization_context& ctx) const { ctx.add(auth_plugin_data); }
};
// Serialize a complete message
template <class Serializable>
inline std::uint8_t serialize_top_level(
const Serializable& input,
std::vector<std::uint8_t>& to,
std::uint8_t seqnum = 0,
std::size_t frame_size = max_packet_size
)
{
serialization_context ctx(to, frame_size);
input.serialize(ctx);
return ctx.write_frame_headers(seqnum);
}
} // namespace detail
} // namespace mysql
} // namespace boost
//
// Implementations
//
namespace boost {
namespace mysql {
namespace detail {
// Maps from an actual value to a protocol_field_type (for execute statement)
inline protocol_field_type to_protocol_field_type(field_kind kind)
{
switch (kind)
{
case field_kind::null: return protocol_field_type::null;
case field_kind::int64: return protocol_field_type::longlong;
case field_kind::uint64: return protocol_field_type::longlong;
case field_kind::string: return protocol_field_type::string;
case field_kind::blob: return protocol_field_type::blob;
case field_kind::float_: return protocol_field_type::float_;
case field_kind::double_: return protocol_field_type::double_;
case field_kind::date: return protocol_field_type::date;
case field_kind::datetime: return protocol_field_type::datetime;
case field_kind::time: return protocol_field_type::time;
default: BOOST_ASSERT(false); return protocol_field_type::null;
}
}
// Returns the collation ID's first byte (for login packets)
inline std::uint8_t get_collation_first_byte(std::uint32_t collation_id)
{
return static_cast<std::uint8_t>(collation_id % 0xff);
}
} // namespace detail
} // namespace mysql
} // namespace boost
void boost::mysql::detail::execute_stmt_command::serialize(serialization_context& ctx) const
{
// The wire layout is as follows:
// command ID
// std::uint32_t statement_id;
// std::uint8_t flags;
// std::uint32_t iteration_count;
// if num_params > 0:
// NULL bitmap
// std::uint8_t new_params_bind_flag;
// array<meta_packet, num_params> meta;
// protocol_field_type type;
// std::uint8_t unsigned_flag;
// array<field_view, num_params> params;
constexpr int1 command_id{0x17};
constexpr int1 flags{0};
constexpr int4 iteration_count{1};
constexpr int1 new_params_bind_flag{1};
// header
ctx.serialize(command_id, int4{statement_id}, flags, iteration_count);
// Number of parameters
auto num_params = params.size();
if (num_params > 0)
{
// NULL bitmap
null_bitmap_generator null_gen(params);
while (!null_gen.done())
ctx.add(null_gen.next());
// new parameters bind flag
new_params_bind_flag.serialize(ctx);
// value metadata
for (field_view param : params)
{
field_kind kind = param.kind();
protocol_field_type type = to_protocol_field_type(kind);
std::uint8_t unsigned_flag = kind == field_kind::uint64 ? std::uint8_t(0x80) : std::uint8_t(0);
ctx.add(static_cast<std::uint8_t>(type));
ctx.add(unsigned_flag);
}
// actual values
for (field_view param : params)
{
serialize_binary_field(ctx, param);
}
}
}
void boost::mysql::detail::login_request::serialize(serialization_context& ctx) const
{
ctx.serialize(
int4{negotiated_capabilities.get()}, // client_flag
int4{max_packet_size}, // max_packet_size
int1{get_collation_first_byte(collation_id)}, // character_set
string_fixed<23>{}, // filler (all zeros)
string_null{username},
string_lenenc{to_string(auth_response)} // we require CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA
);
if (negotiated_capabilities.has(CLIENT_CONNECT_WITH_DB))
{
string_null{database}.serialize(ctx); // database
}
string_null{auth_plugin_name}.serialize(ctx); // client_plugin_name
}
void boost::mysql::detail::ssl_request::serialize(serialization_context& ctx) const
{
ctx.serialize(
int4{negotiated_capabilities.get()}, // client_flag
int4{max_packet_size}, // max_packet_size
int1{get_collation_first_byte(collation_id)}, // character_set,
string_fixed<23>{} // filler, all zeros
);
}
#endif