Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-18 08:52:42

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_START_EXECUTION_HPP
0009 #define BOOST_MYSQL_IMPL_INTERNAL_SANSIO_START_EXECUTION_HPP
0010 
0011 #include <boost/mysql/character_set.hpp>
0012 #include <boost/mysql/client_errc.hpp>
0013 #include <boost/mysql/constant_string_view.hpp>
0014 #include <boost/mysql/diagnostics.hpp>
0015 #include <boost/mysql/error_code.hpp>
0016 #include <boost/mysql/format_sql.hpp>
0017 
0018 #include <boost/mysql/detail/algo_params.hpp>
0019 #include <boost/mysql/detail/any_execution_request.hpp>
0020 #include <boost/mysql/detail/execution_processor/execution_processor.hpp>
0021 #include <boost/mysql/detail/next_action.hpp>
0022 #include <boost/mysql/detail/output_string.hpp>
0023 #include <boost/mysql/detail/resultset_encoding.hpp>
0024 
0025 #include <boost/mysql/impl/internal/coroutine.hpp>
0026 #include <boost/mysql/impl/internal/protocol/impl/serialization_context.hpp>
0027 #include <boost/mysql/impl/internal/protocol/serialization.hpp>
0028 #include <boost/mysql/impl/internal/sansio/connection_state_data.hpp>
0029 #include <boost/mysql/impl/internal/sansio/read_resultset_head.hpp>
0030 
0031 #include <boost/core/span.hpp>
0032 
0033 namespace boost {
0034 namespace mysql {
0035 namespace detail {
0036 
0037 // A serializable to generate the query in the write buffer without copies
0038 struct query_with_params
0039 {
0040     constant_string_view query;
0041     span<const format_arg> args;
0042     format_options opts;
0043 
0044     void serialize(serialization_context& ctx) const
0045     {
0046         // Create a format context
0047         auto fmt_ctx = access::construct<format_context_base>(output_string_ref::create(ctx), opts);
0048 
0049         // Serialize the query header
0050         ctx.add(0x03);
0051 
0052         // Serialize the actual query
0053         vformat_sql_to(fmt_ctx, query, args);
0054 
0055         // Check for errors
0056         ctx.add_error(fmt_ctx.error_state());
0057     }
0058 };
0059 
0060 class start_execution_algo
0061 {
0062     int resume_point_{0};
0063     read_resultset_head_algo read_head_st_;
0064     any_execution_request req_;
0065     bool is_top_level_;
0066 
0067     std::uint8_t& seqnum() { return processor().sequence_number(); }
0068     execution_processor& processor() { return read_head_st_.processor(); }
0069 
0070     static resultset_encoding get_encoding(any_execution_request::type_t type)
0071     {
0072         switch (type)
0073         {
0074         case any_execution_request::type_t::query:
0075         case any_execution_request::type_t::query_with_params: return resultset_encoding::text;
0076         case any_execution_request::type_t::stmt: return resultset_encoding::binary;
0077         default: BOOST_ASSERT(false); return resultset_encoding::text;  // LCOV_EXCL_LINE
0078         }
0079     }
0080 
0081     next_action write_query_with_params(
0082         connection_state_data& st,
0083         any_execution_request::data_t::query_with_params_t data
0084     )
0085     {
0086         // Determine format options
0087         if (st.current_charset.name == nullptr)
0088         {
0089             return error_code(client_errc::unknown_character_set);
0090         }
0091         format_options opts{st.current_charset, st.backslash_escapes};
0092 
0093         // Write the request
0094         return st.write(query_with_params{data.query, data.args, opts}, seqnum());
0095     }
0096 
0097     next_action write_stmt(connection_state_data& st, any_execution_request::data_t::stmt_t data)
0098     {
0099         if (data.num_params != data.params.size())
0100             return error_code(client_errc::wrong_num_params);
0101         return st.write(execute_stmt_command{data.stmt_id, data.params}, seqnum());
0102     }
0103 
0104     next_action compose_request(connection_state_data& st)
0105     {
0106         switch (req_.type)
0107         {
0108         case any_execution_request::type_t::query: return st.write(query_command{req_.data.query}, seqnum());
0109         case any_execution_request::type_t::query_with_params:
0110             return write_query_with_params(st, req_.data.query_with_params);
0111         case any_execution_request::type_t::stmt: return write_stmt(st, req_.data.stmt);
0112         default: BOOST_ASSERT(false); return next_action();  // LCOV_EXCL_LINE
0113         }
0114     }
0115 
0116 public:
0117     // We pass false to the read head algo's constructor because it's a subordinate algos.
0118     // This suppresses state checks.
0119     start_execution_algo(start_execution_algo_params params, bool is_top_level = true) noexcept
0120         : read_head_st_({params.proc}, false), req_(params.req), is_top_level_(is_top_level)
0121     {
0122     }
0123 
0124     next_action resume(connection_state_data& st, diagnostics& diag, error_code ec)
0125     {
0126         next_action act;
0127 
0128         switch (resume_point_)
0129         {
0130         case 0:
0131             // Check connection status. The check is only correct if we're the top-level algorithm
0132             if (is_top_level_)
0133             {
0134                 ec = st.check_status_ready();
0135                 if (ec)
0136                     return ec;
0137             }
0138 
0139             // Reset the processor
0140             processor().reset(get_encoding(req_.type), st.meta_mode);
0141 
0142             // Send the execution request
0143             BOOST_MYSQL_YIELD(resume_point_, 1, compose_request(st))
0144             if (ec)
0145                 return ec;
0146 
0147             // If the request was sent successfully, and we're the top-level algorithm,
0148             // we're now running a multi-function operation. The status flag is cleared
0149             // by the other algorithms on error or when an OK packet is received
0150             if (is_top_level_)
0151                 st.status = connection_status::engaged_in_multi_function;
0152 
0153             // Read the first resultset's head and return its result
0154             while (!(act = read_head_st_.resume(st, diag, ec)).is_done())
0155                 BOOST_MYSQL_YIELD(resume_point_, 2, act)
0156 
0157             // If there was an error, we're no longer running a multi-function operation
0158             if (act.error())
0159             {
0160                 if (is_top_level_)
0161                     st.status = connection_status::ready;
0162                 return act;
0163             }
0164 
0165             // If we received the final OK packet, we're no longer running a multi-function operation
0166             if (processor().is_complete() && is_top_level_)
0167                 st.status = connection_status::ready;
0168         }
0169 
0170         return next_action();
0171     }
0172 };
0173 
0174 }  // namespace detail
0175 }  // namespace mysql
0176 }  // namespace boost
0177 
0178 #endif