static_results_impl.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  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_STATIC_RESULTS_IMPL_HPP
  8. #define BOOST_MYSQL_DETAIL_EXECUTION_PROCESSOR_STATIC_RESULTS_IMPL_HPP
  9. #include <boost/mysql/detail/config.hpp>
  10. #ifdef BOOST_MYSQL_CXX14
  11. #include <boost/mysql/diagnostics.hpp>
  12. #include <boost/mysql/field_view.hpp>
  13. #include <boost/mysql/metadata.hpp>
  14. #include <boost/mysql/metadata_collection_view.hpp>
  15. #include <boost/mysql/string_view.hpp>
  16. #include <boost/mysql/detail/execution_processor/execution_processor.hpp>
  17. #include <boost/mysql/detail/typing/readable_field_traits.hpp>
  18. #include <boost/mysql/detail/typing/row_traits.hpp>
  19. #include <boost/assert.hpp>
  20. #include <boost/mp11/algorithm.hpp>
  21. #include <boost/mp11/integer_sequence.hpp>
  22. #include <array>
  23. #include <cstddef>
  24. namespace boost {
  25. namespace mysql {
  26. namespace detail {
  27. using results_reset_fn_t = void (*)(void*);
  28. using results_parse_fn_t =
  29. error_code (*)(span<const std::size_t> pos_map, span<const field_view> from, void* to);
  30. struct results_resultset_descriptor
  31. {
  32. std::size_t num_columns;
  33. name_table_t name_table;
  34. meta_check_fn_t meta_check;
  35. results_parse_fn_t parse_fn;
  36. };
  37. struct static_per_resultset_data
  38. {
  39. std::size_t meta_offset{};
  40. std::size_t meta_size{};
  41. std::size_t info_offset{};
  42. std::size_t info_size{};
  43. bool has_ok_packet_data{false}; // The OK packet information is default constructed, or actual data?
  44. std::uint64_t affected_rows{}; // OK packet data
  45. std::uint64_t last_insert_id{}; // OK packet data
  46. std::uint16_t warnings{}; // OK packet data
  47. bool is_out_params{false}; // Does this resultset contain OUT param information?
  48. };
  49. class results_external_data
  50. {
  51. public:
  52. struct ptr_data
  53. {
  54. void* rows;
  55. std::size_t* pos_map;
  56. static_per_resultset_data* per_resultset;
  57. };
  58. results_external_data(
  59. span<const results_resultset_descriptor> desc,
  60. results_reset_fn_t reset,
  61. ptr_data ptr
  62. ) noexcept
  63. : desc_(desc), reset_(reset), ptr_(ptr)
  64. {
  65. }
  66. void set_pointers(ptr_data ptr) noexcept { ptr_ = ptr; }
  67. std::size_t num_resultsets() const noexcept { return desc_.size(); }
  68. std::size_t num_columns(std::size_t idx) const noexcept
  69. {
  70. BOOST_ASSERT(idx < num_resultsets());
  71. return desc_[idx].num_columns;
  72. }
  73. name_table_t name_table(std::size_t idx) const noexcept
  74. {
  75. BOOST_ASSERT(idx < num_resultsets());
  76. return desc_[idx].name_table;
  77. }
  78. meta_check_fn_t meta_check_fn(std::size_t idx) const noexcept
  79. {
  80. BOOST_ASSERT(idx < num_resultsets());
  81. return desc_[idx].meta_check;
  82. }
  83. results_parse_fn_t parse_fn(std::size_t idx) const noexcept
  84. {
  85. BOOST_ASSERT(idx < num_resultsets());
  86. return desc_[idx].parse_fn;
  87. }
  88. results_reset_fn_t reset_fn() const noexcept { return reset_; }
  89. void* rows() const noexcept { return ptr_.rows; }
  90. span<std::size_t> pos_map(std::size_t idx) const noexcept
  91. {
  92. return span<std::size_t>(ptr_.pos_map, num_columns(idx));
  93. }
  94. static_per_resultset_data& per_result(std::size_t idx) const noexcept
  95. {
  96. BOOST_ASSERT(idx < num_resultsets());
  97. return ptr_.per_resultset[idx];
  98. }
  99. private:
  100. span<const results_resultset_descriptor> desc_;
  101. results_reset_fn_t reset_;
  102. ptr_data ptr_;
  103. };
  104. class static_results_erased_impl final : public execution_processor
  105. {
  106. public:
  107. static_results_erased_impl(results_external_data ext) noexcept : ext_(ext) {}
  108. results_external_data& ext_data() noexcept { return ext_; }
  109. metadata_collection_view get_meta(std::size_t index) const noexcept
  110. {
  111. const auto& resultset_data = ext_.per_result(index);
  112. return metadata_collection_view(meta_.data() + resultset_data.meta_offset, resultset_data.meta_size);
  113. }
  114. std::uint64_t get_affected_rows(std::size_t index) const noexcept
  115. {
  116. return ext_.per_result(index).affected_rows;
  117. }
  118. std::uint64_t get_last_insert_id(std::size_t index) const noexcept
  119. {
  120. return ext_.per_result(index).last_insert_id;
  121. }
  122. unsigned get_warning_count(std::size_t index) const noexcept { return ext_.per_result(index).warnings; }
  123. string_view get_info(std::size_t index) const noexcept
  124. {
  125. const auto& resultset_data = ext_.per_result(index);
  126. return string_view(info_.data() + resultset_data.info_offset, resultset_data.info_size);
  127. }
  128. bool get_is_out_params(std::size_t index) const noexcept { return ext_.per_result(index).is_out_params; }
  129. private:
  130. // Virtual implementations
  131. BOOST_MYSQL_DECL
  132. void reset_impl() noexcept override final;
  133. BOOST_MYSQL_DECL
  134. error_code on_head_ok_packet_impl(const ok_view& pack, diagnostics& diag) override final;
  135. BOOST_MYSQL_DECL
  136. void on_num_meta_impl(std::size_t num_columns) override final;
  137. BOOST_MYSQL_DECL
  138. error_code on_meta_impl(const coldef_view& coldef, bool is_last, diagnostics& diag) override final;
  139. BOOST_MYSQL_DECL
  140. error_code on_row_impl(span<const std::uint8_t> msg, const output_ref&, std::vector<field_view>& fields)
  141. override final;
  142. BOOST_MYSQL_DECL
  143. error_code on_row_ok_packet_impl(const ok_view& pack) override final;
  144. void on_row_batch_start_impl() override final {}
  145. void on_row_batch_finish_impl() override final {}
  146. // Data
  147. results_external_data ext_;
  148. std::vector<metadata> meta_;
  149. std::vector<char> info_;
  150. std::size_t resultset_index_{0};
  151. // Helpers
  152. span<std::size_t> current_pos_map() noexcept { return ext_.pos_map(resultset_index_ - 1); }
  153. span<const std::size_t> current_pos_map() const noexcept { return ext_.pos_map(resultset_index_ - 1); }
  154. name_table_t current_name_table() const noexcept { return ext_.name_table(resultset_index_ - 1); }
  155. static_per_resultset_data& current_resultset() noexcept { return ext_.per_result(resultset_index_ - 1); }
  156. metadata_collection_view current_resultset_meta() const noexcept
  157. {
  158. return get_meta(resultset_index_ - 1);
  159. }
  160. BOOST_MYSQL_DECL
  161. static_per_resultset_data& add_resultset();
  162. BOOST_MYSQL_DECL
  163. error_code on_ok_packet_impl(const ok_view& pack);
  164. error_code meta_check(diagnostics& diag) const
  165. {
  166. return ext_.meta_check_fn(resultset_index_ - 1)(current_pos_map(), current_resultset_meta(), diag);
  167. }
  168. };
  169. template <class... StaticRow>
  170. using results_rows_t = std::tuple<std::vector<underlying_row_t<StaticRow>>...>;
  171. template <class... StaticRow>
  172. struct results_fns
  173. {
  174. using rows_t = results_rows_t<StaticRow...>;
  175. struct reset_fn
  176. {
  177. rows_t& obj;
  178. template <std::size_t I>
  179. void operator()(boost::mp11::mp_size_t<I>) const noexcept
  180. {
  181. std::get<I>(obj).clear();
  182. }
  183. };
  184. static void reset(void* rows_ptr) noexcept
  185. {
  186. auto& rows = *static_cast<rows_t*>(rows_ptr);
  187. boost::mp11::mp_for_each<boost::mp11::mp_iota_c<sizeof...(StaticRow)>>(reset_fn{rows});
  188. }
  189. template <std::size_t I>
  190. static error_code do_parse(span<const std::size_t> pos_map, span<const field_view> from, void* to)
  191. {
  192. using StaticRowT = mp11::mp_at_c<mp11::mp_list<StaticRow...>, I>;
  193. auto& v = std::get<I>(*static_cast<rows_t*>(to));
  194. v.emplace_back();
  195. return parse<StaticRowT>(pos_map, from, v.back());
  196. }
  197. template <std::size_t I>
  198. static constexpr results_resultset_descriptor create_descriptor()
  199. {
  200. using StaticRowT = mp11::mp_at_c<mp11::mp_list<StaticRow...>, I>;
  201. return {
  202. get_row_size<StaticRowT>(),
  203. get_row_name_table<StaticRowT>(),
  204. &meta_check<StaticRowT>,
  205. &do_parse<I>,
  206. };
  207. }
  208. template <std::size_t... I>
  209. static constexpr std::array<results_resultset_descriptor, sizeof...(StaticRow)> create_descriptors(mp11::index_sequence<
  210. I...>)
  211. {
  212. return {{create_descriptor<I>()...}};
  213. }
  214. };
  215. template <class... StaticRow>
  216. BOOST_INLINE_CONSTEXPR std::array<results_resultset_descriptor, sizeof...(StaticRow)>
  217. results_resultset_descriptor_table = results_fns<StaticRow...>::create_descriptors(
  218. mp11::make_index_sequence<sizeof...(StaticRow)>()
  219. );
  220. template <std::size_t I, class... StaticRow>
  221. using rows_span_t = boost::span<
  222. const typename std::tuple_element<I, std::tuple<underlying_row_t<StaticRow>...>>::type>;
  223. template <BOOST_MYSQL_STATIC_ROW... StaticRow>
  224. class static_results_impl
  225. {
  226. // Data that requires knowing template params
  227. struct
  228. {
  229. results_rows_t<StaticRow...> rows;
  230. std::array<std::size_t, max_num_columns<StaticRow...>> pos_map{};
  231. std::array<static_per_resultset_data, sizeof...(StaticRow)> per_resultset{};
  232. } data_;
  233. // The type-erased impl, that will use pointers to the above storage
  234. static_results_erased_impl impl_;
  235. results_external_data::ptr_data ptr_data() noexcept
  236. {
  237. return {
  238. &data_.rows,
  239. data_.pos_map.data(),
  240. data_.per_resultset.data(),
  241. };
  242. }
  243. void set_pointers() noexcept { impl_.ext_data().set_pointers(ptr_data()); }
  244. public:
  245. static_results_impl() noexcept
  246. : impl_(results_external_data(
  247. results_resultset_descriptor_table<StaticRow...>,
  248. &results_fns<StaticRow...>::reset,
  249. ptr_data()
  250. ))
  251. {
  252. }
  253. static_results_impl(const static_results_impl& rhs) : data_(rhs.data_), impl_(rhs.impl_)
  254. {
  255. set_pointers();
  256. }
  257. static_results_impl(static_results_impl&& rhs) noexcept
  258. : data_(std::move(rhs.data_)), impl_(std::move(rhs.impl_))
  259. {
  260. set_pointers();
  261. }
  262. static_results_impl& operator=(const static_results_impl& rhs)
  263. {
  264. data_ = rhs.data_;
  265. impl_ = rhs.impl_;
  266. set_pointers();
  267. return *this;
  268. }
  269. static_results_impl& operator=(static_results_impl&& rhs)
  270. {
  271. data_ = std::move(rhs.data_);
  272. impl_ = std::move(rhs.impl_);
  273. set_pointers();
  274. return *this;
  275. }
  276. // User facing
  277. template <std::size_t I>
  278. rows_span_t<I, StaticRow...> get_rows() const noexcept
  279. {
  280. return std::get<I>(data_.rows);
  281. }
  282. const static_results_erased_impl& get_interface() const noexcept { return impl_; }
  283. static_results_erased_impl& get_interface() noexcept { return impl_; }
  284. };
  285. } // namespace detail
  286. } // namespace mysql
  287. } // namespace boost
  288. #ifdef BOOST_MYSQL_HEADER_ONLY
  289. #include <boost/mysql/impl/static_results_impl.ipp>
  290. #endif
  291. #endif // BOOST_MYSQL_CXX14
  292. #endif