prepare_statement.hpp 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  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_IMPL_INTERNAL_SANSIO_PREPARE_STATEMENT_HPP
  8. #define BOOST_MYSQL_IMPL_INTERNAL_SANSIO_PREPARE_STATEMENT_HPP
  9. #include <boost/mysql/diagnostics.hpp>
  10. #include <boost/mysql/error_code.hpp>
  11. #include <boost/mysql/statement.hpp>
  12. #include <boost/mysql/detail/algo_params.hpp>
  13. #include <boost/mysql/detail/next_action.hpp>
  14. #include <boost/mysql/impl/internal/coroutine.hpp>
  15. #include <boost/mysql/impl/internal/protocol/deserialization.hpp>
  16. #include <boost/mysql/impl/internal/sansio/connection_state_data.hpp>
  17. namespace boost {
  18. namespace mysql {
  19. namespace detail {
  20. class read_prepare_statement_response_algo
  21. {
  22. int resume_point_{0};
  23. diagnostics* diag_;
  24. std::uint8_t sequence_number_{0};
  25. unsigned remaining_meta_{0};
  26. statement res_;
  27. error_code process_response(connection_state_data& st)
  28. {
  29. prepare_stmt_response response{};
  30. auto err = deserialize_prepare_stmt_response(st.reader.message(), st.flavor, response, *diag_);
  31. if (err)
  32. return err;
  33. res_ = access::construct<statement>(response.id, response.num_params);
  34. remaining_meta_ = response.num_columns + response.num_params;
  35. return error_code();
  36. }
  37. public:
  38. read_prepare_statement_response_algo(diagnostics* diag, std::uint8_t seqnum) noexcept
  39. : diag_(diag), sequence_number_(seqnum)
  40. {
  41. }
  42. std::uint8_t& sequence_number() { return sequence_number_; }
  43. diagnostics& diag() { return *diag_; }
  44. next_action resume(connection_state_data& st, error_code ec)
  45. {
  46. if (ec)
  47. return ec;
  48. switch (resume_point_)
  49. {
  50. case 0:
  51. // Note: diagnostics should have been cleaned by other algos
  52. // Read response
  53. BOOST_MYSQL_YIELD(resume_point_, 1, st.read(sequence_number_))
  54. // Process response
  55. ec = process_response(st);
  56. if (ec)
  57. return ec;
  58. // Server sends now one packet per parameter and field.
  59. // We ignore these for now.
  60. for (; remaining_meta_ > 0u; --remaining_meta_)
  61. BOOST_MYSQL_YIELD(resume_point_, 2, st.read(sequence_number_))
  62. }
  63. return next_action();
  64. }
  65. statement result(const connection_state_data&) const { return res_; }
  66. };
  67. class prepare_statement_algo
  68. {
  69. int resume_point_{0};
  70. read_prepare_statement_response_algo read_response_st_;
  71. string_view stmt_sql_;
  72. public:
  73. prepare_statement_algo(prepare_statement_algo_params params) noexcept
  74. : read_response_st_(params.diag, 0u), stmt_sql_(params.stmt_sql)
  75. {
  76. }
  77. next_action resume(connection_state_data& st, error_code ec)
  78. {
  79. next_action act;
  80. switch (resume_point_)
  81. {
  82. case 0:
  83. // Clear diagnostics
  84. read_response_st_.diag().clear();
  85. // Send request
  86. BOOST_MYSQL_YIELD(
  87. resume_point_,
  88. 1,
  89. st.write(prepare_stmt_command{stmt_sql_}, read_response_st_.sequence_number())
  90. )
  91. if (ec)
  92. return ec;
  93. // Read response
  94. while (!(act = read_response_st_.resume(st, ec)).is_done())
  95. BOOST_MYSQL_YIELD(resume_point_, 2, act)
  96. return act;
  97. }
  98. return next_action();
  99. }
  100. statement result(const connection_state_data& st) const { return read_response_st_.result(st); }
  101. };
  102. } // namespace detail
  103. } // namespace mysql
  104. } // namespace boost
  105. #endif