results_impl.hpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. //
  2. // Copyright (c) 2019-2023 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 BHO_MYSQL_DETAIL_EXECUTION_PROCESSOR_RESULTS_IMPL_HPP
  8. #define BHO_MYSQL_DETAIL_EXECUTION_PROCESSOR_RESULTS_IMPL_HPP
  9. #include <asio2/bho/mysql/diagnostics.hpp>
  10. #include <asio2/bho/mysql/error_code.hpp>
  11. #include <asio2/bho/mysql/field_view.hpp>
  12. #include <asio2/bho/mysql/metadata.hpp>
  13. #include <asio2/bho/mysql/metadata_collection_view.hpp>
  14. #include <asio2/bho/mysql/rows_view.hpp>
  15. #include <asio2/bho/mysql/string_view.hpp>
  16. #include <asio2/bho/mysql/detail/config.hpp>
  17. #include <asio2/bho/mysql/detail/execution_processor/execution_processor.hpp>
  18. #include <asio2/bho/mysql/detail/row_impl.hpp>
  19. #include <asio2/bho/assert.hpp>
  20. namespace bho {
  21. namespace mysql {
  22. namespace detail {
  23. struct per_resultset_data
  24. {
  25. std::size_t num_columns{}; // Number of columns this resultset has
  26. std::size_t meta_offset{}; // Offset into the vector of metadata
  27. std::size_t field_offset; // Offset into the vector of fields (append mode only)
  28. std::size_t num_rows{}; // Number of rows this resultset has (append mode only)
  29. std::uint64_t affected_rows{}; // OK packet data
  30. std::uint64_t last_insert_id{}; // OK packet data
  31. std::uint16_t warnings{}; // OK packet data
  32. std::size_t info_offset{}; // Offset into the vector of info characters
  33. std::size_t info_size{}; // Number of characters that this resultset's info string has
  34. bool has_ok_packet_data{false}; // The OK packet information is default constructed, or actual data?
  35. bool is_out_params{false}; // Does this resultset contain OUT param information?
  36. };
  37. // A container similar to a vector with SBO. To avoid depending on BHO.Container
  38. class resultset_container
  39. {
  40. bool first_has_data_{false};
  41. per_resultset_data first_;
  42. std::vector<per_resultset_data> rest_;
  43. public:
  44. resultset_container() = default;
  45. std::size_t size() const noexcept { return !first_has_data_ ? 0 : rest_.size() + 1; }
  46. bool empty() const noexcept { return !first_has_data_; }
  47. void clear() noexcept
  48. {
  49. first_has_data_ = false;
  50. rest_.clear();
  51. }
  52. per_resultset_data& operator[](std::size_t i) noexcept
  53. {
  54. return const_cast<per_resultset_data&>(const_cast<const resultset_container&>(*this)[i]);
  55. }
  56. const per_resultset_data& operator[](std::size_t i) const noexcept
  57. {
  58. BHO_ASSERT(i < size());
  59. return i == 0 ? first_ : rest_[i - 1];
  60. }
  61. per_resultset_data& back() noexcept
  62. {
  63. return const_cast<per_resultset_data&>(const_cast<const resultset_container&>(*this).back());
  64. }
  65. const per_resultset_data& back() const noexcept
  66. {
  67. BHO_ASSERT(first_has_data_);
  68. return rest_.empty() ? first_ : rest_.back();
  69. }
  70. BHO_MYSQL_DECL per_resultset_data& emplace_back();
  71. };
  72. // Rows for all resultsets are stored in a single rows_impl object.
  73. // - When a row batch is started, we record how many fields we had before the batch.
  74. // - When rows are read, fields are allocated in the rows_impl object, then deserialized against
  75. // the allocated storage. At this point, strings/blobs point into the connection read buffer.
  76. // - When a row batch is finished, we copy strings/blobs into the rows_impl, then transform them
  77. // into offsets to allow rows_impl to grow.
  78. // - When the final OK packet is received, offsets are transformed back into views.
  79. class results_impl final : public execution_processor
  80. {
  81. public:
  82. results_impl() = default;
  83. BHO_MYSQL_DECL
  84. row_view get_out_params() const noexcept;
  85. std::size_t num_resultsets() const noexcept { return per_result_.size(); }
  86. rows_view get_rows(std::size_t index) const noexcept
  87. {
  88. const auto& resultset_data = per_result_[index];
  89. return access::construct<rows_view>(
  90. rows_.fields().data() + resultset_data.field_offset,
  91. resultset_data.num_rows * resultset_data.num_columns,
  92. resultset_data.num_columns
  93. );
  94. }
  95. metadata_collection_view get_meta(std::size_t index) const noexcept
  96. {
  97. const auto& resultset_data = get_resultset(index);
  98. return metadata_collection_view(
  99. meta_.data() + resultset_data.meta_offset,
  100. resultset_data.num_columns
  101. );
  102. }
  103. std::uint64_t get_affected_rows(std::size_t index) const noexcept
  104. {
  105. return get_resultset(index).affected_rows;
  106. }
  107. std::uint64_t get_last_insert_id(std::size_t index) const noexcept
  108. {
  109. return get_resultset(index).last_insert_id;
  110. }
  111. unsigned get_warning_count(std::size_t index) const noexcept { return get_resultset(index).warnings; }
  112. string_view get_info(std::size_t index) const noexcept
  113. {
  114. const auto& resultset_data = get_resultset(index);
  115. return string_view(info_.data() + resultset_data.info_offset, resultset_data.info_size);
  116. }
  117. bool get_is_out_params(std::size_t index) const noexcept { return get_resultset(index).is_out_params; }
  118. results_impl& get_interface() noexcept { return *this; }
  119. private:
  120. // Virtual impls
  121. BHO_MYSQL_DECL
  122. void reset_impl() noexcept override final;
  123. BHO_MYSQL_DECL
  124. void on_num_meta_impl(std::size_t num_columns) override final;
  125. BHO_MYSQL_DECL
  126. error_code on_head_ok_packet_impl(const ok_view& pack, diagnostics&) override final;
  127. BHO_MYSQL_DECL
  128. error_code on_meta_impl(const coldef_view&, bool, diagnostics&) override final;
  129. BHO_MYSQL_DECL
  130. error_code on_row_impl(span<const std::uint8_t> msg, const output_ref&, std::vector<field_view>&)
  131. override final;
  132. BHO_MYSQL_DECL
  133. error_code on_row_ok_packet_impl(const ok_view& pack) override final;
  134. BHO_MYSQL_DECL
  135. void on_row_batch_start_impl() override final;
  136. BHO_MYSQL_DECL
  137. void on_row_batch_finish_impl() override final;
  138. // Data
  139. std::vector<metadata> meta_;
  140. resultset_container per_result_;
  141. std::vector<char> info_;
  142. row_impl rows_;
  143. std::size_t num_fields_at_batch_start_{no_batch};
  144. // Auxiliar
  145. static constexpr std::size_t no_batch = std::size_t(-1);
  146. bool has_active_batch() const noexcept { return num_fields_at_batch_start_ != no_batch; }
  147. BHO_MYSQL_DECL
  148. void finish_batch();
  149. per_resultset_data& current_resultset() noexcept
  150. {
  151. BHO_ASSERT(!per_result_.empty());
  152. return per_result_.back();
  153. }
  154. const per_resultset_data& current_resultset() const noexcept
  155. {
  156. BHO_ASSERT(!per_result_.empty());
  157. return per_result_.back();
  158. }
  159. BHO_MYSQL_DECL
  160. per_resultset_data& add_resultset();
  161. BHO_MYSQL_DECL
  162. void on_ok_packet_impl(const ok_view& pack);
  163. const per_resultset_data& get_resultset(std::size_t index) const noexcept
  164. {
  165. BHO_ASSERT(index < per_result_.size());
  166. return per_result_[index];
  167. }
  168. metadata_collection_view current_resultset_meta() const noexcept
  169. {
  170. return get_meta(per_result_.size() - 1);
  171. }
  172. };
  173. } // namespace detail
  174. } // namespace mysql
  175. } // namespace bho
  176. #ifdef BHO_MYSQL_HEADER_ONLY
  177. #include <asio2/bho/mysql/impl/results_impl.ipp>
  178. #endif
  179. #endif