prepare_statement.hpp 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. //
  2. // Copyright (c) 2019-2025 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. std::uint8_t sequence_number_{0};
  24. unsigned remaining_meta_{0};
  25. statement res_;
  26. error_code process_response(connection_state_data& st, diagnostics& diag)
  27. {
  28. prepare_stmt_response response{};
  29. auto err = deserialize_prepare_stmt_response(st.reader.message(), st.flavor, response, diag);
  30. if (err)
  31. return err;
  32. res_ = access::construct<statement>(response.id, response.num_params);
  33. remaining_meta_ = response.num_columns + response.num_params;
  34. return error_code();
  35. }
  36. public:
  37. read_prepare_statement_response_algo(std::uint8_t seqnum) noexcept : sequence_number_(seqnum) {}
  38. std::uint8_t& sequence_number() { return sequence_number_; }
  39. next_action resume(connection_state_data& st, diagnostics& diag, error_code ec)
  40. {
  41. if (ec)
  42. return ec;
  43. switch (resume_point_)
  44. {
  45. case 0:
  46. // Read response
  47. BOOST_MYSQL_YIELD(resume_point_, 1, st.read(sequence_number_))
  48. // Process response
  49. ec = process_response(st, diag);
  50. if (ec)
  51. return ec;
  52. // Server sends now one packet per parameter and field.
  53. // We ignore these for now.
  54. for (; remaining_meta_ > 0u; --remaining_meta_)
  55. BOOST_MYSQL_YIELD(resume_point_, 2, st.read(sequence_number_))
  56. }
  57. return next_action();
  58. }
  59. statement result(const connection_state_data&) const { return res_; }
  60. };
  61. class prepare_statement_algo
  62. {
  63. int resume_point_{0};
  64. read_prepare_statement_response_algo read_response_st_;
  65. string_view stmt_sql_;
  66. public:
  67. prepare_statement_algo(prepare_statement_algo_params params) noexcept
  68. : read_response_st_(0u), stmt_sql_(params.stmt_sql)
  69. {
  70. }
  71. next_action resume(connection_state_data& st, diagnostics& diag, error_code ec)
  72. {
  73. next_action act;
  74. switch (resume_point_)
  75. {
  76. case 0:
  77. // Check status
  78. ec = st.check_status_ready();
  79. if (ec)
  80. return ec;
  81. // Send request
  82. BOOST_MYSQL_YIELD(
  83. resume_point_,
  84. 1,
  85. st.write(prepare_stmt_command{stmt_sql_}, read_response_st_.sequence_number())
  86. )
  87. if (ec)
  88. return ec;
  89. // Read response
  90. while (!(act = read_response_st_.resume(st, diag, ec)).is_done())
  91. BOOST_MYSQL_YIELD(resume_point_, 2, act)
  92. return act;
  93. }
  94. return next_action();
  95. }
  96. statement result(const connection_state_data& st) const { return read_response_st_.result(st); }
  97. };
  98. } // namespace detail
  99. } // namespace mysql
  100. } // namespace boost
  101. #endif