Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-17 08:39:17

0001 //
0002 // Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)
0003 //
0004 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0005 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0006 //
0007 
0008 #ifndef BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_SERIALIZATION_HPP
0009 #define BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_SERIALIZATION_HPP
0010 
0011 #include <boost/mysql/error_code.hpp>
0012 #include <boost/mysql/field_view.hpp>
0013 #include <boost/mysql/string_view.hpp>
0014 
0015 #include <boost/mysql/impl/internal/protocol/capabilities.hpp>
0016 #include <boost/mysql/impl/internal/protocol/frame_header.hpp>
0017 #include <boost/mysql/impl/internal/protocol/impl/binary_protocol.hpp>
0018 #include <boost/mysql/impl/internal/protocol/impl/null_bitmap.hpp>
0019 #include <boost/mysql/impl/internal/protocol/impl/protocol_field_type.hpp>
0020 #include <boost/mysql/impl/internal/protocol/impl/protocol_types.hpp>
0021 #include <boost/mysql/impl/internal/protocol/impl/serialization_context.hpp>
0022 
0023 #include <boost/assert.hpp>
0024 
0025 #include <cstddef>
0026 #include <cstdint>
0027 
0028 namespace boost {
0029 namespace mysql {
0030 namespace detail {
0031 
0032 // quit
0033 struct quit_command
0034 {
0035     void serialize(serialization_context& ctx) const { ctx.add(0x01); }
0036 };
0037 
0038 // ping
0039 struct ping_command
0040 {
0041     void serialize(serialization_context& ctx) const { ctx.add(0x0e); }
0042 };
0043 
0044 // reset_connection
0045 struct reset_connection_command
0046 {
0047     void serialize(serialization_context& ctx) const { ctx.add(0x1f); }
0048 };
0049 
0050 // query
0051 struct query_command
0052 {
0053     string_view query;
0054 
0055     void serialize(serialization_context& ctx) const
0056     {
0057         ctx.add(0x03);
0058         string_eof{query}.serialize(ctx);
0059     }
0060 };
0061 
0062 // prepare_statement
0063 struct prepare_stmt_command
0064 {
0065     string_view stmt;
0066 
0067     void serialize(serialization_context& ctx) const
0068     {
0069         ctx.add(0x16);
0070         string_eof{stmt}.serialize(ctx);
0071     }
0072 };
0073 
0074 // execute statement
0075 struct execute_stmt_command
0076 {
0077     std::uint32_t statement_id;
0078     span<const field_view> params;
0079 
0080     inline void serialize(serialization_context& ctx) const;
0081 };
0082 
0083 // close statement
0084 struct close_stmt_command
0085 {
0086     std::uint32_t statement_id;
0087     void serialize(serialization_context& ctx) const { ctx.serialize_fixed(int1{0x19}, int4{statement_id}); }
0088 };
0089 
0090 // Login request
0091 struct login_request
0092 {
0093     capabilities negotiated_capabilities;  // capabilities
0094     std::uint32_t max_packet_size;
0095     std::uint32_t collation_id;
0096     string_view username;
0097     span<const std::uint8_t> auth_response;
0098     string_view database;
0099     string_view auth_plugin_name;
0100 
0101     inline void serialize(serialization_context& ctx) const;
0102 };
0103 
0104 // SSL request
0105 struct ssl_request
0106 {
0107     capabilities negotiated_capabilities;
0108     std::uint32_t max_packet_size;
0109     std::uint32_t collation_id;
0110 
0111     inline void serialize(serialization_context& ctx) const;
0112 };
0113 
0114 // Auth switch response
0115 struct auth_switch_response
0116 {
0117     span<const std::uint8_t> auth_plugin_data;
0118 
0119     void serialize(serialization_context& ctx) const { ctx.add(auth_plugin_data); }
0120 };
0121 
0122 // The result of serialize_top_level (similar to system::result,
0123 // doesn't track source locations)
0124 struct serialize_top_level_result
0125 {
0126     error_code err;
0127     std::uint8_t seqnum{};
0128 
0129     constexpr serialize_top_level_result(error_code ec) noexcept : err(ec) {}
0130     constexpr serialize_top_level_result(std::uint8_t seqnum) noexcept : seqnum(seqnum) {}
0131 };
0132 
0133 // Serialize a complete message. May fail
0134 template <class Serializable>
0135 inline serialize_top_level_result serialize_top_level(
0136     const Serializable& input,
0137     std::vector<std::uint8_t>& to,
0138     std::uint8_t seqnum = 0,
0139     std::size_t max_buffer_size = static_cast<std::size_t>(-1),
0140     std::size_t max_frame_size = max_packet_size
0141 )
0142 {
0143     std::size_t initial_offset = to.size();
0144     serialization_context ctx(to, max_buffer_size, max_frame_size);
0145     input.serialize(ctx);
0146     auto err = ctx.error();
0147     if (err)
0148         return err;
0149     return ctx.write_frame_headers(seqnum, initial_offset);
0150 }
0151 
0152 // Same, but for cases that can't fail. Does not enforce any limit on buffer size
0153 template <class Serializable>
0154 inline std::uint8_t serialize_top_level_checked(
0155     const Serializable& input,
0156     std::vector<std::uint8_t>& to,
0157     std::uint8_t seqnum = 0,
0158     std::size_t max_frame_size = max_packet_size
0159 )
0160 {
0161     auto res = serialize_top_level(input, to, seqnum, static_cast<std::size_t>(-1), max_frame_size);
0162     BOOST_ASSERT(res.err == error_code());
0163     return res.seqnum;
0164 }
0165 
0166 }  // namespace detail
0167 }  // namespace mysql
0168 }  // namespace boost
0169 
0170 //
0171 // Implementations
0172 //
0173 
0174 namespace boost {
0175 namespace mysql {
0176 namespace detail {
0177 
0178 // Maps from an actual value to a protocol_field_type (for execute statement)
0179 inline protocol_field_type to_protocol_field_type(field_kind kind)
0180 {
0181     switch (kind)
0182     {
0183     case field_kind::null: return protocol_field_type::null;
0184     case field_kind::int64: return protocol_field_type::longlong;
0185     case field_kind::uint64: return protocol_field_type::longlong;
0186     case field_kind::string: return protocol_field_type::string;
0187     case field_kind::blob: return protocol_field_type::blob;
0188     case field_kind::float_: return protocol_field_type::float_;
0189     case field_kind::double_: return protocol_field_type::double_;
0190     case field_kind::date: return protocol_field_type::date;
0191     case field_kind::datetime: return protocol_field_type::datetime;
0192     case field_kind::time: return protocol_field_type::time;
0193     default: BOOST_ASSERT(false); return protocol_field_type::null;  // LCOV_EXCL_LINE
0194     }
0195 }
0196 
0197 // Returns the collation ID's first byte (for login packets)
0198 inline std::uint8_t get_collation_first_byte(std::uint32_t collation_id)
0199 {
0200     return static_cast<std::uint8_t>(collation_id % 0xff);
0201 }
0202 
0203 }  // namespace detail
0204 }  // namespace mysql
0205 }  // namespace boost
0206 
0207 void boost::mysql::detail::execute_stmt_command::serialize(serialization_context& ctx) const
0208 {
0209     // The wire layout is as follows:
0210     //  command ID
0211     //  std::uint32_t statement_id;
0212     //  std::uint8_t flags;
0213     //  std::uint32_t iteration_count;
0214     //  if num_params > 0:
0215     //      NULL bitmap
0216     //      std::uint8_t new_params_bind_flag;
0217     //      array<meta_packet, num_params> meta;
0218     //          protocol_field_type type;
0219     //          std::uint8_t unsigned_flag;
0220     //      array<field_view, num_params> params;
0221 
0222     constexpr int1 command_id{0x17};
0223     constexpr int1 flags{0};
0224     constexpr int4 iteration_count{1};
0225     constexpr int1 new_params_bind_flag{1};
0226 
0227     // header
0228     ctx.serialize_fixed(command_id, int4{statement_id}, flags, iteration_count);
0229 
0230     // Number of parameters
0231     auto num_params = params.size();
0232 
0233     if (num_params > 0)
0234     {
0235         // NULL bitmap
0236         null_bitmap_generator null_gen(params);
0237         while (!null_gen.done())
0238             ctx.add(null_gen.next());
0239 
0240         // new parameters bind flag
0241         new_params_bind_flag.serialize(ctx);
0242 
0243         // value metadata
0244         for (field_view param : params)
0245         {
0246             field_kind kind = param.kind();
0247             protocol_field_type type = to_protocol_field_type(kind);
0248             std::uint8_t unsigned_flag = kind == field_kind::uint64 ? std::uint8_t(0x80) : std::uint8_t(0);
0249             ctx.serialize_fixed(int1{static_cast<std::uint8_t>(type)}, int1{unsigned_flag});
0250         }
0251 
0252         // actual values
0253         for (field_view param : params)
0254         {
0255             serialize_binary_field(ctx, param);
0256         }
0257     }
0258 }
0259 
0260 void boost::mysql::detail::login_request::serialize(serialization_context& ctx) const
0261 {
0262     ctx.serialize_fixed(
0263         int4{negotiated_capabilities.get()},           // client_flag
0264         int4{max_packet_size},                         // max_packet_size
0265         int1{get_collation_first_byte(collation_id)},  //  character_set
0266         string_fixed<23>{}                             // filler (all zeros)
0267     );
0268     ctx.serialize(
0269         string_null{username},
0270         string_lenenc{to_string(auth_response)}  // we require CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA
0271     );
0272     if (negotiated_capabilities.has(CLIENT_CONNECT_WITH_DB))
0273     {
0274         string_null{database}.serialize(ctx);  // database
0275     }
0276     string_null{auth_plugin_name}.serialize(ctx);  //  client_plugin_name
0277 }
0278 
0279 void boost::mysql::detail::ssl_request::serialize(serialization_context& ctx) const
0280 {
0281     ctx.serialize_fixed(
0282         int4{negotiated_capabilities.get()},           // client_flag
0283         int4{max_packet_size},                         // max_packet_size
0284         int1{get_collation_first_byte(collation_id)},  // character_set,
0285         string_fixed<23>{}                             // filler, all zeros
0286     );
0287 }
0288 
0289 #endif