execution_processor.hpp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. //
  2. // Copyright (c) 2019-2024 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)
  3. //
  4. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  5. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. //
  7. #ifndef BOOST_MYSQL_DETAIL_EXECUTION_PROCESSOR_EXECUTION_PROCESSOR_HPP
  8. #define BOOST_MYSQL_DETAIL_EXECUTION_PROCESSOR_EXECUTION_PROCESSOR_HPP
  9. #include <boost/mysql/diagnostics.hpp>
  10. #include <boost/mysql/error_code.hpp>
  11. #include <boost/mysql/field_view.hpp>
  12. #include <boost/mysql/metadata.hpp>
  13. #include <boost/mysql/metadata_mode.hpp>
  14. #include <boost/mysql/string_view.hpp>
  15. #include <boost/mysql/detail/access.hpp>
  16. #include <boost/mysql/detail/coldef_view.hpp>
  17. #include <boost/mysql/detail/ok_view.hpp>
  18. #include <boost/mysql/detail/resultset_encoding.hpp>
  19. #include <boost/assert.hpp>
  20. #include <boost/config.hpp>
  21. #include <boost/core/span.hpp>
  22. #include <cstddef>
  23. #include <cstdint>
  24. #include <limits>
  25. namespace boost {
  26. namespace mysql {
  27. namespace detail {
  28. // A type-erased reference to be used as the output range for static_execution_state
  29. class output_ref
  30. {
  31. // Pointer to the first element of the span
  32. void* data_{};
  33. // Number of elements in the span
  34. std::size_t max_size_{(std::numeric_limits<std::size_t>::max)()};
  35. // Identifier for the type of elements. Index in the resultset type list
  36. std::size_t type_index_{};
  37. // Offset into the span's data (static_execution_state). Otherwise unused
  38. std::size_t offset_{};
  39. public:
  40. constexpr output_ref() noexcept = default;
  41. template <class T>
  42. constexpr output_ref(boost::span<T> span, std::size_t type_index, std::size_t offset = 0) noexcept
  43. : data_(span.data()), max_size_(span.size()), type_index_(type_index), offset_(offset)
  44. {
  45. }
  46. std::size_t max_size() const noexcept { return max_size_; }
  47. std::size_t type_index() const noexcept { return type_index_; }
  48. std::size_t offset() const noexcept { return offset_; }
  49. void set_offset(std::size_t v) noexcept { offset_ = v; }
  50. template <class T>
  51. T& span_element() const noexcept
  52. {
  53. BOOST_ASSERT(data_);
  54. return static_cast<T*>(data_)[offset_];
  55. }
  56. };
  57. class execution_processor
  58. {
  59. public:
  60. virtual ~execution_processor() {}
  61. void reset(resultset_encoding enc, metadata_mode mode) noexcept
  62. {
  63. state_ = state_t::reading_first;
  64. encoding_ = enc;
  65. mode_ = mode;
  66. seqnum_ = 0;
  67. remaining_meta_ = 0;
  68. reset_impl();
  69. }
  70. BOOST_ATTRIBUTE_NODISCARD
  71. error_code on_head_ok_packet(const ok_view& pack, diagnostics& diag)
  72. {
  73. BOOST_ASSERT(is_reading_head());
  74. auto err = on_head_ok_packet_impl(pack, diag);
  75. set_state_for_ok(pack);
  76. return err;
  77. }
  78. void on_num_meta(std::size_t num_columns)
  79. {
  80. BOOST_ASSERT(is_reading_head());
  81. on_num_meta_impl(num_columns);
  82. remaining_meta_ = num_columns;
  83. set_state(state_t::reading_metadata);
  84. }
  85. BOOST_ATTRIBUTE_NODISCARD
  86. error_code on_meta(const coldef_view& pack, diagnostics& diag)
  87. {
  88. BOOST_ASSERT(is_reading_meta());
  89. bool is_last = --remaining_meta_ == 0;
  90. auto err = on_meta_impl(pack, is_last, diag);
  91. if (is_last)
  92. set_state(state_t::reading_rows);
  93. return err;
  94. }
  95. void on_row_batch_start()
  96. {
  97. BOOST_ASSERT(is_reading_rows());
  98. on_row_batch_start_impl();
  99. }
  100. void on_row_batch_finish() { on_row_batch_finish_impl(); }
  101. BOOST_ATTRIBUTE_NODISCARD
  102. error_code on_row(span<const std::uint8_t> msg, const output_ref& ref, std::vector<field_view>& storage)
  103. {
  104. BOOST_ASSERT(is_reading_rows());
  105. return on_row_impl(msg, ref, storage);
  106. }
  107. BOOST_ATTRIBUTE_NODISCARD
  108. error_code on_row_ok_packet(const ok_view& pack)
  109. {
  110. BOOST_ASSERT(is_reading_rows());
  111. auto err = on_row_ok_packet_impl(pack);
  112. set_state_for_ok(pack);
  113. return err;
  114. }
  115. bool is_reading_first() const noexcept { return state_ == state_t::reading_first; }
  116. bool is_reading_first_subseq() const noexcept { return state_ == state_t::reading_first_subseq; }
  117. bool is_reading_head() const noexcept
  118. {
  119. return state_ == state_t::reading_first || state_ == state_t::reading_first_subseq;
  120. }
  121. bool is_reading_meta() const noexcept { return state_ == state_t::reading_metadata; }
  122. bool is_reading_rows() const noexcept { return state_ == state_t::reading_rows; }
  123. bool is_complete() const noexcept { return state_ == state_t::complete; }
  124. resultset_encoding encoding() const noexcept { return encoding_; }
  125. std::uint8_t& sequence_number() noexcept { return seqnum_; }
  126. metadata_mode meta_mode() const noexcept { return mode_; }
  127. protected:
  128. virtual void reset_impl() noexcept = 0;
  129. virtual error_code on_head_ok_packet_impl(const ok_view& pack, diagnostics& diag) = 0;
  130. virtual void on_num_meta_impl(std::size_t num_columns) = 0;
  131. virtual error_code on_meta_impl(const coldef_view& coldef, bool is_last, diagnostics& diag) = 0;
  132. virtual error_code on_row_ok_packet_impl(const ok_view& pack) = 0;
  133. virtual error_code on_row_impl(
  134. span<const std::uint8_t> msg,
  135. const output_ref& ref,
  136. std::vector<field_view>& storage
  137. ) = 0;
  138. virtual void on_row_batch_start_impl() = 0;
  139. virtual void on_row_batch_finish_impl() = 0;
  140. metadata create_meta(const coldef_view& coldef) const
  141. {
  142. return access::construct<metadata>(coldef, mode_ == metadata_mode::full);
  143. }
  144. private:
  145. enum class state_t
  146. {
  147. // waiting for 1st packet, for the 1st resultset
  148. reading_first,
  149. // same, but for subsequent resultsets (distiguised to provide a cleaner xp to
  150. // the user in (static_)execution_state)
  151. reading_first_subseq,
  152. // waiting for metadata packets
  153. reading_metadata,
  154. // waiting for rows
  155. reading_rows,
  156. // done
  157. complete
  158. };
  159. state_t state_{state_t::reading_first};
  160. resultset_encoding encoding_{resultset_encoding::text};
  161. std::uint8_t seqnum_{};
  162. metadata_mode mode_{metadata_mode::minimal};
  163. std::size_t remaining_meta_{};
  164. void set_state(state_t v) noexcept { state_ = v; }
  165. void set_state_for_ok(const ok_view& pack) noexcept
  166. {
  167. if (pack.more_results())
  168. {
  169. set_state(state_t::reading_first_subseq);
  170. }
  171. else
  172. {
  173. set_state(state_t::complete);
  174. }
  175. }
  176. };
  177. } // namespace detail
  178. } // namespace mysql
  179. } // namespace boost
  180. #endif