Back to home page

EIC code displayed by LXR

 
 

    


Warning, file /include/boost/mysql/pipeline.hpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 //
0002 // Copyright (c) 2019-2024 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)
0003 //
0004 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0005 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0006 //
0007 
0008 #ifndef BOOST_MYSQL_PIPELINE_HPP
0009 #define BOOST_MYSQL_PIPELINE_HPP
0010 
0011 #include <boost/mysql/character_set.hpp>
0012 #include <boost/mysql/diagnostics.hpp>
0013 #include <boost/mysql/error_code.hpp>
0014 #include <boost/mysql/field_view.hpp>
0015 #include <boost/mysql/results.hpp>
0016 #include <boost/mysql/statement.hpp>
0017 #include <boost/mysql/string_view.hpp>
0018 
0019 #include <boost/mysql/detail/access.hpp>
0020 #include <boost/mysql/detail/config.hpp>
0021 #include <boost/mysql/detail/execution_processor/execution_processor.hpp>
0022 #include <boost/mysql/detail/pipeline.hpp>
0023 #include <boost/mysql/detail/writable_field_traits.hpp>
0024 
0025 #include <boost/assert.hpp>
0026 #include <boost/core/span.hpp>
0027 #include <boost/variant2/variant.hpp>
0028 
0029 #include <array>
0030 #include <cstdint>
0031 #include <utility>
0032 #include <vector>
0033 
0034 namespace boost {
0035 namespace mysql {
0036 
0037 /**
0038  * \brief (EXPERIMENTAL) A variant-like type holding the response of a single pipeline stage.
0039  * \details
0040  * This is a variant-like type, similar to `boost::system::result`. At any point in time,
0041  * it can contain: \n
0042  *   \li A \ref statement. Will happen if the stage was a prepare statement that succeeded.
0043  *   \li A \ref results. Will happen if the stage was a query or statement execution that succeeded.
0044  *   \li An \ref error_code, \ref diagnostics pair. Will happen if the stage failed, or if it succeeded but
0045  *       it doesn't yield a value (as in close statement, reset connection and set character set).
0046  *
0047  * \par Experimental
0048  * This part of the API is experimental, and may change in successive
0049  * releases without previous notice.
0050  */
0051 class stage_response
0052 {
0053 #ifndef BOOST_MYSQL_DOXYGEN
0054     struct errcode_with_diagnostics
0055     {
0056         error_code ec;
0057         diagnostics diag;
0058     };
0059 
0060     struct
0061     {
0062         variant2::variant<errcode_with_diagnostics, statement, results> value;
0063 
0064         void emplace_results() { value.emplace<results>(); }
0065         void emplace_error() { value.emplace<errcode_with_diagnostics>(); }
0066         detail::execution_processor& get_processor()
0067         {
0068             return detail::access::get_impl(variant2::unsafe_get<2>(value));
0069         }
0070         void set_result(statement s) { value = s; }
0071         void set_error(error_code ec, diagnostics&& diag)
0072         {
0073             value.emplace<0>(errcode_with_diagnostics{ec, std::move(diag)});
0074         }
0075     } impl_;
0076 
0077     friend struct detail::access;
0078 #endif
0079 
0080     bool has_error() const { return impl_.value.index() == 0u; }
0081 
0082     BOOST_MYSQL_DECL
0083     void check_has_results() const;
0084 
0085 public:
0086     /**
0087      * \brief Default constructor.
0088      * \details
0089      * Constructs an object containing an empty error code and diagnostics.
0090      *
0091      * \par Exception safety
0092      * No-throw guarantee.
0093      */
0094     stage_response() = default;
0095 
0096     /**
0097      * \brief Returns true if the object contains a statement.
0098      *
0099      * \par Exception safety
0100      * No-throw guarantee.
0101      */
0102     bool has_statement() const noexcept { return impl_.value.index() == 1u; }
0103 
0104     /**
0105      * \brief Returns true if the object contains a results.
0106      *
0107      * \par Exception safety
0108      * No-throw guarantee.
0109      */
0110     bool has_results() const noexcept { return impl_.value.index() == 2u; }
0111 
0112     /**
0113      * \brief Retrieves the contained error code.
0114      * \details
0115      * If `*this` contains an error, retrieves it.
0116      * Otherwise (if `this->has_statement() || this->has_results()`),
0117      * returns an empty (default-constructed) error code.
0118      *
0119      * \par Exception safety
0120      * No-throw guarantee.
0121      */
0122     error_code error() const noexcept
0123     {
0124         return has_error() ? variant2::unsafe_get<0>(impl_.value).ec : error_code();
0125     }
0126 
0127     /**
0128      * \brief Retrieves the contained diagnostics (lvalue reference accessor).
0129      * \details
0130      * If `*this` contains an error, retrieves the associated diagnostic information
0131      * by copying it.
0132      * Otherwise (if `this->has_statement() || this->has_results()`),
0133      * returns an empty diagnostics object.
0134      *
0135      * \par Exception safety
0136      * Strong guarantee: memory allocations may throw.
0137      */
0138     diagnostics diag() const&
0139     {
0140         return has_error() ? variant2::unsafe_get<0>(impl_.value).diag : diagnostics();
0141     }
0142 
0143     /**
0144      * \brief Retrieves the contained diagnostics (rvalue reference accessor).
0145      * \details
0146      * If `*this` contains an error, retrieves the associated diagnostic information
0147      * by moving it.
0148      * Otherwise (if `this->has_statement() || this->has_results()`),
0149      * returns an empty (default-constructed) error.
0150      *
0151      * \par Exception safety
0152      * No-throw guarantee.
0153      */
0154     diagnostics diag() && noexcept
0155     {
0156         return has_error() ? variant2::unsafe_get<0>(std::move(impl_.value)).diag : diagnostics();
0157     }
0158 
0159     /**
0160      * \brief Retrieves the contained statement or throws an exception.
0161      * \details
0162      * If `*this` contains an statement (`this->has_statement() == true`),
0163      * retrieves it. Otherwise, throws an exception.
0164      *
0165      * \par Exception safety
0166      * Strong guarantee. Throws on invalid input.
0167      * \throws std::invalid_argument If `*this` does not contain a statement.
0168      */
0169     BOOST_MYSQL_DECL
0170     statement as_statement() const;
0171 
0172     /**
0173      * \brief Retrieves the contained statement (unchecked accessor).
0174      * \details
0175      * If `*this` contains an statement,
0176      * retrieves it. Otherwise, the behavior is undefined.
0177      *
0178      * \par Preconditions
0179      * `this->has_statement() == true`
0180      *
0181      * \par Exception safety
0182      * No-throw guarantee.
0183      */
0184     statement get_statement() const noexcept
0185     {
0186         BOOST_ASSERT(has_statement());
0187         return variant2::unsafe_get<1>(impl_.value);
0188     }
0189 
0190     /**
0191      * \brief Retrieves the contained results or throws an exception.
0192      * \details
0193      * If `*this` contains a `results` object (`this->has_results() == true`),
0194      * retrieves a reference to it. Otherwise, throws an exception.
0195      *
0196      * \par Exception safety
0197      * Strong guarantee. Throws on invalid input.
0198      * \throws std::invalid_argument If `this->has_results() == false`
0199      *
0200      * \par Object lifetimes
0201      * The returned reference is valid as long as `*this` is alive
0202      * and hasn't been assigned to.
0203      */
0204     const results& as_results() const&
0205     {
0206         check_has_results();
0207         return variant2::unsafe_get<2>(impl_.value);
0208     }
0209 
0210     /// \copydoc as_results
0211     results&& as_results() &&
0212     {
0213         check_has_results();
0214         return variant2::unsafe_get<2>(std::move(impl_.value));
0215     }
0216 
0217     /**
0218      * \brief Retrieves the contained results (unchecked accessor).
0219      * \details
0220      * If `*this` contains a `results` object, retrieves a reference to it.
0221      * Otherwise, the behavior is undefined.
0222      *
0223      * \par Preconditions
0224      * `this->has_results() == true`
0225      *
0226      * \par Exception safety
0227      * No-throw guarantee.
0228      *
0229      * \par Object lifetimes
0230      * The returned reference is valid as long as `*this` is alive
0231      * and hasn't been assigned to.
0232      */
0233     const results& get_results() const& noexcept
0234     {
0235         BOOST_ASSERT(has_results());
0236         return variant2::unsafe_get<2>(impl_.value);
0237     }
0238 
0239     /// \copydoc get_results
0240     results&& get_results() && noexcept
0241     {
0242         BOOST_ASSERT(has_results());
0243         return variant2::unsafe_get<2>(std::move(impl_.value));
0244     }
0245 };
0246 
0247 /**
0248  * \brief (EXPERIMENTAL) A pipeline request.
0249  * \details
0250  * Contains a collection of pipeline stages, fully describing the work to be performed
0251  * by a pipeline operation.
0252  * Call any of the `add_xxx` functions to append new stages to the request.
0253  *
0254  * \par Experimental
0255  * This part of the API is experimental, and may change in successive
0256  * releases without previous notice.
0257  */
0258 class pipeline_request
0259 {
0260 #ifndef BOOST_MYSQL_DOXYGEN
0261     struct impl_t
0262     {
0263         std::vector<std::uint8_t> buffer_;
0264         std::vector<detail::pipeline_request_stage> stages_;
0265     } impl_;
0266 
0267     friend struct detail::access;
0268 #endif
0269 
0270 public:
0271     /**
0272      * \brief Default constructor.
0273      * \details Constructs an empty pipeline request, with no stages.
0274      *
0275      * \par Exception safety
0276      * No-throw guarantee.
0277      */
0278     pipeline_request() = default;
0279 
0280     /**
0281      * \brief Adds a stage that executes a text query.
0282      * \details
0283      * Creates a stage that will run `query` as a SQL query,
0284      * like \ref any_connection::execute.
0285      *
0286      * \par Exception safety
0287      * Strong guarantee. Memory allocations may throw.
0288      *
0289      * \par Object lifetimes
0290      * query is copied into the request and need not be kept alive after this function returns.
0291      */
0292     BOOST_MYSQL_DECL
0293     pipeline_request& add_execute(string_view query);
0294 
0295     /**
0296      * \brief Adds a stage that executes a prepared statement.
0297      * \details
0298      * Creates a stage that runs
0299      * `stmt` bound to any parameters passed in `params`, like \ref any_connection::execute
0300      * and \ref statement::bind. For example, `add_execute(stmt, 42, "John")` has
0301      * effects equivalent to `conn.execute(stmt.bind(42, "John"))`.
0302      *
0303      * \par Exception safety
0304      * Strong guarantee. Throws if the supplied number of parameters doesn't match the number
0305      * of parameters expected by the statement. Additionally, memory allocations may throw.
0306      * \throws std::invalid_argument If `sizeof...(params) != stmt.num_params()`
0307      *
0308      * \par Preconditions
0309      * The passed statement should be valid (`stmt.valid() == true`).
0310      *
0311      * \par Object lifetimes
0312      * Any objects pointed to by `params` are copied into the request and
0313      * need not be kept alive after this function returns.
0314      *
0315      * \par Type requirements
0316      * Any type satisfying `WritableField` can be used as a parameter.
0317      * This includes all types that can be used with \ref statement::bind,
0318      * including scalar types, strings, blobs and optionals.
0319      */
0320     template <BOOST_MYSQL_WRITABLE_FIELD... WritableField>
0321     pipeline_request& add_execute(statement stmt, const WritableField&... params)
0322     {
0323         std::array<field_view, sizeof...(WritableField)> params_arr{{detail::to_field(params)...}};
0324         return add_execute_range(stmt, params_arr);
0325     }
0326 
0327     /**
0328      * \brief Adds a stage that executes a prepared statement.
0329      * \details
0330      * Creates a stage that runs
0331      * `stmt` bound to any parameters passed in `params`, like \ref any_connection::execute
0332      * and \ref statement::bind. For example, `add_execute_range(stmt, params)` has
0333      * effects equivalent to `conn.execute(stmt.bind(params.begin(), params.end()))`.
0334      * \n
0335      * This function can be used instead of \ref add_execute when the number of actual parameters
0336      * of a statement is not known at compile time.
0337      *
0338      * \par Exception safety
0339      * Strong guarantee. Throws if the supplied number of parameters doesn't match the number
0340      * of parameters expected by the statement. Additionally, memory allocations may throw.
0341      * \throws std::invalid_argument If `params.size() != stmt.num_params()`
0342      *
0343      * \par Preconditions
0344      * The passed statement should be valid (`stmt.valid() == true`).
0345      *
0346      * \par Object lifetimes
0347      * The `params` range is copied into the request and
0348      * needs not be kept alive after this function returns.
0349      */
0350     BOOST_MYSQL_DECL
0351     pipeline_request& add_execute_range(statement stmt, span<const field_view> params);
0352 
0353     /**
0354      * \brief Adds a prepare statement stage.
0355      * \details
0356      * Creates a stage that prepares a statement server-side. The resulting
0357      * stage has effects equivalent to `conn.prepare_statement(stmt_sql)`.
0358      *
0359      * \par Exception safety
0360      * Strong guarantee. Memory allocations may throw.
0361      *
0362      * \par Object lifetimes
0363      * stmt_sql is copied into the request and need not be kept alive after this function returns.
0364      */
0365     BOOST_MYSQL_DECL
0366     pipeline_request& add_prepare_statement(string_view stmt_sql);
0367 
0368     /**
0369      * \brief Adds a close statement stage.
0370      * \details
0371      * Creates a stage that closes a prepared statement. The resulting
0372      * stage has effects equivalent to `conn.close_statement(stmt)`.
0373      *
0374      * \par Exception safety
0375      * Strong guarantee. Memory allocations may throw.
0376      *
0377      * \par Preconditions
0378      * The passed statement should be valid (`stmt.valid() == true`).
0379      */
0380     BOOST_MYSQL_DECL pipeline_request& add_close_statement(statement stmt);
0381 
0382     /**
0383      * \brief Adds a reset connection stage.
0384      * \details
0385      * Creates a stage that resets server-side session state. The resulting
0386      * stage has effects equivalent to `conn.reset_connection()`.
0387      *
0388      * \par Exception safety
0389      * Strong guarantee. Memory allocations may throw.
0390      */
0391     BOOST_MYSQL_DECL pipeline_request& add_reset_connection();
0392 
0393     /**
0394      * \brief Adds a set character set stage.
0395      * \details
0396      * Creates a stage that sets the connection's character set.
0397      * The resulting stage has effects equivalent to `conn.set_character_set(charset)`.
0398      *
0399      * \par Exception safety
0400      * Strong guarantee. Throws if the supplied character set name is not valid
0401      * (i.e. `charset.name` contains non-ASCII characters).
0402      * The check is performed as a hardening measure, and never happens with
0403      * the character sets provided by this library.
0404      *
0405      * Additionally, memory allocations may throw.
0406      * \throws std::invalid_argument If `charset.name` contains non-ASCII characters.
0407      *
0408      * \par Preconditions
0409      * The passed character set should not be default-constructed
0410      * (`charset.name != nullptr`).
0411      */
0412     BOOST_MYSQL_DECL pipeline_request& add_set_character_set(character_set charset);
0413 
0414     /**
0415      * \brief Removes all stages in the pipeline request, making the object empty again.
0416      * \details
0417      * Can be used to re-use a single request object for multiple pipeline operations.
0418      *
0419      * \par Exception safety
0420      * No-throw guarantee.
0421      */
0422     void clear() noexcept
0423     {
0424         impl_.buffer_.clear();
0425         impl_.stages_.clear();
0426     }
0427 };
0428 
0429 }  // namespace mysql
0430 }  // namespace boost
0431 
0432 #ifdef BOOST_MYSQL_HEADER_ONLY
0433 #include <boost/mysql/impl/pipeline.ipp>
0434 #endif
0435 
0436 #endif