gnss-sim/3rdparty/boost/mysql/impl/internal/sansio/set_character_set.hpp

138 lines
4.0 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_SANSIO_SET_CHARACTER_SET_HPP
#define BOOST_MYSQL_IMPL_INTERNAL_SANSIO_SET_CHARACTER_SET_HPP
#include <boost/mysql/character_set.hpp>
#include <boost/mysql/client_errc.hpp>
#include <boost/mysql/diagnostics.hpp>
#include <boost/mysql/format_sql.hpp>
#include <boost/mysql/detail/algo_params.hpp>
#include <boost/mysql/detail/next_action.hpp>
#include <boost/mysql/impl/internal/coroutine.hpp>
#include <boost/mysql/impl/internal/protocol/deserialization.hpp>
#include <boost/mysql/impl/internal/protocol/serialization.hpp>
#include <boost/mysql/impl/internal/sansio/connection_state_data.hpp>
#include <boost/system/result.hpp>
#include <cstdint>
namespace boost {
namespace mysql {
namespace detail {
// Securely compose a SET NAMES statement
inline system::result<std::string> compose_set_names(character_set charset)
{
// The character set should not be default-constructed
BOOST_ASSERT(charset.name != nullptr);
// For security, if the character set has non-ascii characters in it name, reject it.
format_context ctx(format_options{ascii_charset, true});
ctx.append_raw("SET NAMES ").append_value(charset.name);
return std::move(ctx).get();
}
class read_set_character_set_response_algo
{
int resume_point_{0};
diagnostics* diag_;
character_set charset_;
std::uint8_t seqnum_{0};
public:
read_set_character_set_response_algo(diagnostics* diag, character_set charset, std::uint8_t seqnum)
: diag_(diag), charset_(charset), seqnum_(seqnum)
{
}
character_set charset() const { return charset_; }
diagnostics& diag() { return *diag_; }
std::uint8_t& sequence_number() { return seqnum_; }
next_action resume(connection_state_data& st, error_code ec)
{
// SET NAMES never returns rows. Using execute requires us to allocate
// a results object, which we can avoid by simply sending the query and reading the OK response.
switch (resume_point_)
{
case 0:
// Read the response
BOOST_MYSQL_YIELD(resume_point_, 1, st.read(seqnum_))
if (ec)
return ec;
// Verify it's what we expected
ec = st.deserialize_ok(*diag_);
if (ec)
return ec;
// If we were successful, update the character set
st.current_charset = charset_;
}
return next_action();
}
};
class set_character_set_algo
{
int resume_point_{0};
read_set_character_set_response_algo read_response_st_;
next_action compose_request(connection_state_data& st)
{
auto q = compose_set_names(read_response_st_.charset());
if (q.has_error())
return q.error();
return st.write(query_command{q.value()}, read_response_st_.sequence_number());
}
public:
set_character_set_algo(set_character_set_algo_params params) noexcept
: read_response_st_(params.diag, params.charset, 0u)
{
}
next_action resume(connection_state_data& st, error_code ec)
{
next_action act;
// SET NAMES never returns rows. Using execute requires us to allocate
// a results object, which we can avoid by simply sending the query and reading the OK response.
switch (resume_point_)
{
case 0:
// Setup
read_response_st_.diag().clear();
// Send the execution request
BOOST_MYSQL_YIELD(resume_point_, 1, compose_request(st))
if (ec)
return ec;
// Read the response
while (!(act = read_response_st_.resume(st, ec)).is_done())
BOOST_MYSQL_YIELD(resume_point_, 2, act)
return act;
}
return next_action();
}
};
} // namespace detail
} // namespace mysql
} // namespace boost
#endif