Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-13 08:41:59

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_SANSIO_SET_CHARACTER_SET_HPP
0009 #define BOOST_MYSQL_IMPL_INTERNAL_SANSIO_SET_CHARACTER_SET_HPP
0010 
0011 #include <boost/mysql/character_set.hpp>
0012 #include <boost/mysql/client_errc.hpp>
0013 #include <boost/mysql/diagnostics.hpp>
0014 #include <boost/mysql/format_sql.hpp>
0015 
0016 #include <boost/mysql/detail/algo_params.hpp>
0017 #include <boost/mysql/detail/next_action.hpp>
0018 
0019 #include <boost/mysql/impl/internal/coroutine.hpp>
0020 #include <boost/mysql/impl/internal/protocol/deserialization.hpp>
0021 #include <boost/mysql/impl/internal/protocol/serialization.hpp>
0022 #include <boost/mysql/impl/internal/sansio/connection_state_data.hpp>
0023 
0024 #include <boost/system/result.hpp>
0025 
0026 #include <cstdint>
0027 
0028 namespace boost {
0029 namespace mysql {
0030 namespace detail {
0031 
0032 // Securely compose a SET NAMES statement
0033 inline system::result<std::string> compose_set_names(character_set charset)
0034 {
0035     // The character set should not be default-constructed
0036     BOOST_ASSERT(charset.name != nullptr);
0037 
0038     // For security, if the character set has non-ascii characters in it name, reject it.
0039     format_context ctx(format_options{ascii_charset, true});
0040     ctx.append_raw("SET NAMES ").append_value(charset.name);
0041     return std::move(ctx).get();
0042 }
0043 
0044 class read_set_character_set_response_algo
0045 {
0046     int resume_point_{0};
0047     character_set charset_;
0048     std::uint8_t seqnum_{0};
0049 
0050 public:
0051     read_set_character_set_response_algo(character_set charset, std::uint8_t seqnum)
0052         : charset_(charset), seqnum_(seqnum)
0053     {
0054     }
0055     character_set charset() const { return charset_; }
0056     std::uint8_t& sequence_number() { return seqnum_; }
0057 
0058     next_action resume(connection_state_data& st, diagnostics& diag, error_code ec)
0059     {
0060         // SET NAMES never returns rows. Using execute requires us to allocate
0061         // a results object, which we can avoid by simply sending the query and reading the OK response.
0062         switch (resume_point_)
0063         {
0064         case 0:
0065 
0066             // Read the response
0067             BOOST_MYSQL_YIELD(resume_point_, 1, st.read(seqnum_))
0068             if (ec)
0069                 return ec;
0070 
0071             // Verify it's what we expected
0072             ec = st.deserialize_ok(diag);
0073             if (ec)
0074                 return ec;
0075 
0076             // If we were successful, update the character set
0077             st.current_charset = charset_;
0078         }
0079 
0080         return next_action();
0081     }
0082 };
0083 
0084 class set_character_set_algo
0085 {
0086     int resume_point_{0};
0087     read_set_character_set_response_algo read_response_st_;
0088 
0089     next_action compose_request(connection_state_data& st)
0090     {
0091         auto q = compose_set_names(read_response_st_.charset());
0092         if (q.has_error())
0093             return q.error();
0094         return st.write(query_command{q.value()}, read_response_st_.sequence_number());
0095     }
0096 
0097 public:
0098     set_character_set_algo(set_character_set_algo_params params) noexcept
0099         : read_response_st_(params.charset, 0u)
0100     {
0101     }
0102 
0103     next_action resume(connection_state_data& st, diagnostics& diag, error_code ec)
0104     {
0105         next_action act;
0106 
0107         // SET NAMES never returns rows. Using execute requires us to allocate
0108         // a results object, which we can avoid by simply sending the query and reading the OK response.
0109         switch (resume_point_)
0110         {
0111         case 0:
0112 
0113             // Check status
0114             ec = st.check_status_ready();
0115             if (ec)
0116                 return ec;
0117 
0118             // Send the execution request
0119             BOOST_MYSQL_YIELD(resume_point_, 1, compose_request(st))
0120             if (ec)
0121                 return ec;
0122 
0123             // Read the response
0124             while (!(act = read_response_st_.resume(st, diag, ec)).is_done())
0125                 BOOST_MYSQL_YIELD(resume_point_, 2, act)
0126             return act;
0127         }
0128 
0129         return next_action();
0130     }
0131 };
0132 
0133 }  // namespace detail
0134 }  // namespace mysql
0135 }  // namespace boost
0136 
0137 #endif