Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-17 08:39:21

0001 //
0002 // Copyright (c) 2019-2025 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_FORMAT_SQL_HPP
0009 #define BOOST_MYSQL_FORMAT_SQL_HPP
0010 
0011 #include <boost/mysql/character_set.hpp>
0012 #include <boost/mysql/constant_string_view.hpp>
0013 #include <boost/mysql/error_code.hpp>
0014 #include <boost/mysql/string_view.hpp>
0015 
0016 #include <boost/mysql/detail/access.hpp>
0017 #include <boost/mysql/detail/config.hpp>
0018 #include <boost/mysql/detail/format_sql.hpp>
0019 #include <boost/mysql/detail/output_string.hpp>
0020 
0021 #include <boost/config.hpp>
0022 #include <boost/core/span.hpp>
0023 #include <boost/system/result.hpp>
0024 
0025 #include <initializer_list>
0026 #include <string>
0027 #include <type_traits>
0028 #include <utility>
0029 
0030 namespace boost {
0031 namespace mysql {
0032 
0033 /**
0034  * \brief An extension point to customize SQL formatting.
0035  * \details
0036  * This type can be specialized for custom types to make them formattable.
0037  * This makes them satisfy the `Formattable` concept, and thus usable in
0038  * \ref format_sql and similar functions.
0039  * \n
0040  * A `formatter` specialization for a type `T` should have the following form:
0041  * ```
0042  * template <>
0043  * struct formatter<T>
0044  * {
0045  *     const char* parse(const char* begin, const char* end); // parse format specs
0046  *     void format(const T& value, format_context_base& ctx) const; // perform the actual formatting
0047  * };
0048  * ```
0049  * \n
0050  * When a value with a custom formatter is formatted (using \ref format_sql or a similar
0051  * function), the library performs the following actions: \n
0052  *   - An instance of `formatter<T>` is default-constructed, where `T` is the type of the
0053  *     value being formatted after removing const and references.
0054  *   - The `parse` function is invoked on the constructed instance,
0055  *     with `[begin, end)` pointing to the format specifier
0056  *     that the current replacement field has. If `parse` finds specifiers it understands, it should
0057  *     remember them, usually setting some flag in the `formatter` instance.
0058  *     `parse` must return an iterator to the first
0059  *     unparsed character in the range (or the `end` iterator, if everything was parsed).
0060  *     Some examples of what would get passed to `parse`:
0061  *       - In `"SELECT {}"`, the range would be empty.
0062  *       - In `"SELECT {:abc}"`, the range would be `"abc"`.
0063  *       - In `"SELECT {0:i}"`, the range would be `"i"`.
0064  *   - If `parse` didn't manage to parse all the passed specifiers (i.e. if it returned an iterator
0065  *     different to the passed's end), a \ref client_errc::format_string_invalid_specifier
0066  *     is emitted and the format operation finishes.
0067  *   - Otherwise, `format` is invoked on the formatter instance, passing the value to be formatted
0068  *     and the \ref format_context_base where format operation is running.
0069  *     This function should perform the actual formatting, usually calling
0070  *     \ref format_sql_to on the passed context.
0071  *
0072  * \n
0073  * Don't specialize `formatter` for built-in types, like `int`, `std::string` or
0074  * optionals (formally, any type satisfying `WritableField`), as the specializations will be ignored.
0075  */
0076 template <class T>
0077 struct formatter
0078 #ifndef BOOST_MYSQL_DOXYGEN
0079     : detail::formatter_is_unspecialized
0080 {
0081 }
0082 #endif
0083 ;
0084 
0085 /**
0086  * \brief A type-erased reference to a `Formattable` value.
0087  * \details
0088  * This type can hold references to any value that satisfies the `Formattable`
0089  * concept. The `formattable_ref` type itself satisfies `Formattable`,
0090  * and can thus be used as an argument to format functions.
0091  *
0092  * \par Object lifetimes
0093  * This is a non-owning type. It should be only used as a function argument,
0094  * to avoid lifetime issues.
0095  */
0096 class formattable_ref
0097 {
0098     detail::formattable_ref_impl impl_;
0099 #ifndef BOOST_MYSQL_DOXYGEN
0100     friend struct detail::access;
0101 #endif
0102 public:
0103     /**
0104      * \brief Constructor.
0105      * \details
0106      * Constructs a type-erased formattable reference from a concrete
0107      * `Formattable` type.
0108      * \n
0109      * This constructor participates in overload resolution only if
0110      * the passed value meets the `Formattable` concept and
0111      * is not a `formattable_ref` or a reference to one.
0112      *
0113      * \par Exception safety
0114      * No-throw guarantee.
0115      *
0116      * \par Object lifetimes
0117      * value is potentially stored as a view, although some cheap-to-copy
0118      * types may be stored as values.
0119      */
0120     template <
0121         BOOST_MYSQL_FORMATTABLE Formattable
0122 #ifndef BOOST_MYSQL_DOXYGEN
0123         ,
0124         class = typename std::enable_if<
0125             detail::is_formattable_type<Formattable>() &&
0126             !detail::is_formattable_ref<Formattable>::value>::type
0127 #endif
0128         >
0129     formattable_ref(Formattable&& value) noexcept
0130         : impl_(detail::make_formattable_ref(std::forward<Formattable>(value)))
0131     {
0132     }
0133 };
0134 
0135 /**
0136  * \brief A named format argument, to be used in initializer lists.
0137  * \details
0138  * Represents a name, value pair to be passed to a formatting function.
0139  * This type should only be used in initializer lists, as a function argument.
0140  *
0141  * \par Object lifetimes
0142  * This is a non-owning type. Both the argument name and value are stored
0143  * as views.
0144  */
0145 class format_arg
0146 {
0147 #ifndef BOOST_MYSQL_DOXYGEN
0148     struct
0149     {
0150         string_view name;
0151         detail::formattable_ref_impl value;
0152     } impl_;
0153 
0154     friend struct detail::access;
0155 #endif
0156 
0157 public:
0158     /**
0159      * \brief Constructor.
0160      * \details
0161      * Constructs an argument from a name and a value.
0162      *
0163      * \par Exception safety
0164      * No-throw guarantee.
0165      *
0166      * \par Object lifetimes
0167      * Both `name` and `value` are stored as views.
0168      */
0169     format_arg(string_view name, formattable_ref value) noexcept
0170         : impl_{name, detail::access::get_impl(value)}
0171     {
0172     }
0173 };
0174 
0175 /**
0176  * \brief Base class for concrete format contexts.
0177  * \details
0178  * Conceptually, a format context contains: \n
0179  *   \li The result string. Output operations append characters to this output string.
0180  *       `format_context_base` is agnostic to the output string type.
0181  *   \li \ref format_options required to format values.
0182  *   \li An error state (\ref error_state) that is set by output operations when they fail.
0183  *       The error state is propagated to \ref basic_format_context::get.
0184  * \n
0185  * References to this class are useful when you need to manipulate
0186  * a format context without knowing the type of the actual context that will be used,
0187  * like when specializing \ref formatter.
0188  * \n
0189  * This class can't be
0190  * instantiated directly - use \ref basic_format_context, instead.
0191  * Do not subclass it, either.
0192  */
0193 class format_context_base
0194 {
0195 #ifndef BOOST_MYSQL_DOXYGEN
0196     struct
0197     {
0198         detail::output_string_ref output;
0199         format_options opts;
0200         error_code ec;
0201     } impl_;
0202 
0203     friend struct detail::access;
0204     friend class detail::format_state;
0205 #endif
0206 
0207     BOOST_MYSQL_DECL void format_arg(detail::formattable_ref_impl arg, string_view format_spec);
0208 
0209 protected:
0210     format_context_base(detail::output_string_ref out, format_options opts, error_code ec = {}) noexcept
0211         : impl_{out, opts, ec}
0212     {
0213     }
0214 
0215     format_context_base(detail::output_string_ref out, const format_context_base& rhs) noexcept
0216         : impl_{out, rhs.impl_.opts, rhs.impl_.ec}
0217     {
0218     }
0219 
0220     void assign(const format_context_base& rhs) noexcept
0221     {
0222         // output never changes, it always points to the derived object's storage
0223         impl_.opts = rhs.impl_.opts;
0224         impl_.ec = rhs.impl_.ec;
0225     }
0226 
0227 public:
0228     /**
0229      * \brief Adds raw SQL to the output string (low level).
0230      * \details
0231      * Adds raw, unescaped SQL to the output string. Doesn't alter the error state.
0232      * \n
0233      * By default, the passed SQL should be available at compile-time.
0234      * Use \ref runtime if you need to use runtime values.
0235      * \n
0236      * This is a low level function. In general, prefer \ref format_sql_to, instead.
0237      *
0238      * \par Exception safety
0239      * Basic guarantee. Memory allocations may throw.
0240      *
0241      * \par Object lifetimes
0242      * The passed string is copied as required and doesn't need to be kept alive.
0243      */
0244     format_context_base& append_raw(constant_string_view sql)
0245     {
0246         impl_.output.append(sql.get());
0247         return *this;
0248     }
0249 
0250     /**
0251      * \brief Formats a value and adds it to the output string (low level).
0252      * \details
0253      * value is formatted according to its type, applying the passed format specifiers.
0254      * If formatting generates an error (for instance, a string with invalid encoding is passed),
0255      * the error state may be set.
0256      * \n
0257      * This is a low level function. In general, prefer \ref format_sql_to, instead.
0258      *
0259      * \par Exception safety
0260      * Basic guarantee. Memory allocations may throw.
0261      *
0262      * \par Errors
0263      * The error state may be updated with the following errors: \n
0264      * \li \ref client_errc::invalid_encoding if a string with byte sequences that can't be decoded
0265      *          with the current character set is passed.
0266      * \li \ref client_errc::unformattable_value if a NaN or infinity `float` or `double` is passed.
0267      * \li \ref client_errc::format_string_invalid_specifier if `format_specifiers` includes
0268      *          specifiers not supported by the type being formatted.
0269      * \li Any other error code that user-supplied formatter specializations may add using \ref add_error.
0270      */
0271     format_context_base& append_value(
0272         formattable_ref value,
0273         constant_string_view format_specifiers = string_view()
0274     )
0275     {
0276         format_arg(detail::access::get_impl(value), format_specifiers.get());
0277         return *this;
0278     }
0279 
0280     /**
0281      * \brief Adds an error to the current error state.
0282      * \details
0283      * This function can be used by custom formatters to report that they
0284      * received a value that can't be formatted. For instance, it's used by
0285      * the built-in string formatter when a string with an invalid encoding is supplied.
0286      * \n
0287      * If the error state is not set before calling this function, the error
0288      * state is updated to `ec`. Otherwise, the error is ignored.
0289      * This implies that once the error state is set, it can't be reset.
0290      * \n
0291      * \par Exception safety
0292      * No-throw guarantee.
0293      */
0294     void add_error(error_code ec) noexcept
0295     {
0296         if (!impl_.ec)
0297             impl_.ec = ec;
0298     }
0299 
0300     /**
0301      * \brief Retrieves the current error state.
0302      *
0303      * \par Exception safety
0304      * No-throw guarantee.
0305      */
0306     error_code error_state() const noexcept { return impl_.ec; }
0307 
0308     /**
0309      * \brief Retrieves the format options.
0310      *
0311      * \par Exception safety
0312      * No-throw guarantee.
0313      */
0314     format_options format_opts() const noexcept { return impl_.opts; }
0315 };
0316 
0317 /**
0318  * \brief Format context for incremental SQL formatting.
0319  * \details
0320  * The primary interface for incremental SQL formatting. Contrary to \ref format_context_base,
0321  * this type is aware of the output string's actual type. `basic_format_context` owns
0322  * an instance of `OutputString`. Format operations will append characters to such string.
0323  * \n
0324  * Objects of this type are single-use: once the result has been retrieved using \ref get,
0325  * they cannot be re-used. This is a move-only type.
0326  */
0327 template <BOOST_MYSQL_OUTPUT_STRING OutputString>
0328 class basic_format_context : public format_context_base
0329 {
0330     OutputString output_{};
0331 
0332     detail::output_string_ref ref() noexcept { return detail::output_string_ref::create(output_); }
0333 
0334 public:
0335     /**
0336      * \brief Constructor.
0337      * \details
0338      * Uses a default-constructed `OutputString` as output string, and an empty
0339      * error code as error state. This constructor can only be called if `OutputString`
0340      * is default-constructible.
0341      *
0342      * \par Exception safety
0343      * Strong guarantee: exceptions thrown by default-constructing `OutputString` are propagated.
0344      */
0345     explicit basic_format_context(format_options opts)
0346 #ifndef BOOST_MYSQL_DOXYGEN  // TODO: remove when https://github.com/boostorg/docca/issues/169 gets done
0347         noexcept(std::is_nothrow_default_constructible<OutputString>::value)
0348 #endif
0349         : format_context_base(ref(), opts)
0350     {
0351     }
0352 
0353     /**
0354      * \brief Constructor.
0355      * \details
0356      * Move constructs an `OutputString` using `storage`. After construction,
0357      * the output string is cleared. Uses an empty
0358      * error code as error state. This constructor allows re-using existing
0359      * memory for the output string.
0360      * \n
0361      *
0362      * \par Exception safety
0363      * Basic guarantee: exceptions thrown by move-constructing `OutputString` are propagated.
0364      */
0365     basic_format_context(format_options opts, OutputString&& storage)
0366 #ifndef BOOST_MYSQL_DOXYGEN  // TODO: remove when https://github.com/boostorg/docca/issues/169 gets done
0367         noexcept(std::is_nothrow_move_constructible<OutputString>::value)
0368 #endif
0369         : format_context_base(ref(), opts), output_(std::move(storage))
0370     {
0371         output_.clear();
0372     }
0373 
0374 #ifndef BOOST_MYSQL_DOXYGEN
0375     basic_format_context(const basic_format_context&) = delete;
0376     basic_format_context& operator=(const basic_format_context&) = delete;
0377 #endif
0378 
0379     /**
0380      * \brief Move constructor.
0381      * \details
0382      * Move constructs an `OutputString` using `rhs`'s output string.
0383      * `*this` will have the same format options and error state than `rhs`.
0384      * `rhs` is left in a valid but unspecified state.
0385      *
0386      * \par Exception safety
0387      * Basic guarantee: exceptions thrown by move-constructing `OutputString` are propagated.
0388      */
0389     basic_format_context(basic_format_context&& rhs)
0390 #ifndef BOOST_MYSQL_DOXYGEN  // TODO: remove when https://github.com/boostorg/docca/issues/169 gets done
0391         noexcept(std::is_nothrow_move_constructible<OutputString>::value)
0392 #endif
0393         : format_context_base(ref(), rhs), output_(std::move(rhs.output_))
0394     {
0395     }
0396 
0397     /**
0398      * \brief Move assignment.
0399      * \details
0400      * Move assigns `rhs`'s output string to `*this` output string.
0401      * `*this` will have the same format options and error state than `rhs`.
0402      * `rhs` is left in a valid but unspecified state.
0403      *
0404      * \par Exception safety
0405      * Basic guarantee: exceptions thrown by move-constructing `OutputString` are propagated.
0406      */
0407     basic_format_context& operator=(basic_format_context&& rhs)
0408 #ifndef BOOST_MYSQL_DOXYGEN  // TODO: remove when https://github.com/boostorg/docca/issues/169 gets done
0409         noexcept(std::is_nothrow_move_assignable<OutputString>::value)
0410 #endif
0411     {
0412         output_ = std::move(rhs.output_);
0413         assign(rhs);
0414         return *this;
0415     }
0416 
0417     /**
0418      * \brief Retrieves the result of the formatting operation.
0419      * \details
0420      * After running the relevant formatting operations (using \ref append_raw,
0421      * \ref append_value or \ref format_sql_to), call this function to retrieve the
0422      * overall result of the operation.
0423      * \n
0424      * If \ref error_state is a non-empty error code, returns it as an error.
0425      * Otherwise, returns the output string, move-constructing it into the `system::result` object.
0426      * \n
0427      * This function is move-only: once called, `*this` is left in a valid but unspecified state.
0428      *
0429      * \par Exception safety
0430      * Basic guarantee: exceptions thrown by move-constructing `OutputString` are propagated.
0431      */
0432     system::result<OutputString> get() &&
0433 #ifndef BOOST_MYSQL_DOXYGEN  // TODO: remove when https://github.com/boostorg/docca/issues/169 gets done
0434         noexcept(std::is_nothrow_move_constructible<OutputString>::value)
0435 #endif
0436     {
0437         auto ec = error_state();
0438         if (ec)
0439             return ec;
0440         return std::move(output_);
0441     }
0442 };
0443 
0444 /**
0445  * \brief Format context for incremental SQL formatting.
0446  * \details
0447  * Convenience type alias for `basic_format_context`'s most common case.
0448  */
0449 using format_context = basic_format_context<std::string>;
0450 
0451 /**
0452  * \brief Composes a SQL query client-side appending it to a format context.
0453  * \details
0454  * Parses `format_str` as a format string, substituting replacement fields (like `{}`, `{1}` or `{name}`)
0455  * by formatted arguments, extracted from `args`.
0456  * \n
0457  * Formatting is performed as if \ref format_context_base::append_raw and
0458  * \ref format_context_base::append_value were called on `ctx`, effectively appending
0459  * characters to its output string.
0460  * \n
0461  * Compared to \ref format_sql, this function is more flexible, allowing the following use cases: \n
0462  *   \li Appending characters to an existing context. Can be used to concatenate the output of successive
0463  *       format operations efficiently.
0464  *   \li Using string types different to `std::string` (works with any \ref basic_format_context).
0465  *   \li Avoiding exceptions (see \ref basic_format_context::get).
0466  *
0467  *
0468  * \par Exception safety
0469  * Basic guarantee. Memory allocations may throw.
0470  *
0471  * \par Errors
0472  * \li \ref client_errc::invalid_encoding if `args` contains a string with byte sequences
0473  *     that can't be decoded with the current character set.
0474  * \li \ref client_errc::unformattable_value if `args` contains a floating-point value
0475  *     that is NaN or infinity.
0476  * \li \ref client_errc::format_string_invalid_specifier if a replacement field includes
0477  *          a specifier not supported by the type being formatted.
0478  * \li Any other error generated by user-defined \ref formatter specializations.
0479  * \li \ref client_errc::format_string_invalid_syntax if `format_str` can't be parsed as
0480  *     a format string.
0481  * \li \ref client_errc::format_string_invalid_encoding if `format_str` contains byte byte sequences
0482  *     that can't be decoded with the current character set.
0483  * \li \ref client_errc::format_string_manual_auto_mix if `format_str` contains a mix of automatic
0484  *     (`{}`) and manual indexed (`{1}`) replacement fields.
0485  * \li \ref client_errc::format_arg_not_found if an argument referenced by `format_str` isn't present
0486  *     in `args` (there aren't enough arguments or a named argument is not found).
0487  */
0488 template <BOOST_MYSQL_FORMATTABLE... Formattable>
0489 void format_sql_to(format_context_base& ctx, constant_string_view format_str, Formattable&&... args)
0490 {
0491     std::initializer_list<format_arg> args_il{
0492         {string_view(), std::forward<Formattable>(args)}
0493         ...
0494     };
0495     detail::vformat_sql_to(ctx, format_str, args_il);
0496 }
0497 
0498 /**
0499  * \copydoc format_sql_to
0500  * \details
0501  * \n
0502  * This overload allows using named arguments.
0503  */
0504 inline void format_sql_to(
0505     format_context_base& ctx,
0506     constant_string_view format_str,
0507     std::initializer_list<format_arg> args
0508 )
0509 {
0510     detail::vformat_sql_to(ctx, format_str, args);
0511 }
0512 
0513 /**
0514  * \brief Composes a SQL query client-side.
0515  * \details
0516  * Parses `format_str` as a format string, substituting replacement fields (like `{}`, `{1}` or `{name}`)
0517  * by formatted arguments, extracted from `args`. `opts` is using to parse the string and format string
0518  * arguments.
0519  * \n
0520  * Formatting is performed as if \ref format_context::append_raw and \ref format_context::append_value
0521  * were called on a context created by this function.
0522  * \n
0523  *
0524  * \par Exception safety
0525  * Strong guarantee. Memory allocations may throw. `boost::system::system_error` is thrown if an error
0526  * is found while formatting. See below for more info.
0527  *
0528  * \par Errors
0529  * \li \ref client_errc::invalid_encoding if `args` contains a string with byte sequences
0530  *     that can't be decoded with the current character set.
0531  * \li \ref client_errc::unformattable_value if `args` contains a floating-point value
0532  *     that is NaN or infinity.
0533  * \li \ref client_errc::format_string_invalid_specifier if a replacement field includes
0534  *          a specifier not supported by the type being formatted.
0535  * \li Any other error generated by user-defined \ref formatter specializations.
0536  * \li \ref client_errc::format_string_invalid_syntax if `format_str` can't be parsed as
0537  *     a format string.
0538  * \li \ref client_errc::format_string_invalid_encoding if `format_str` contains byte byte sequences
0539  *     that can't be decoded with the current character set.
0540  * \li \ref client_errc::format_string_manual_auto_mix if `format_str` contains a mix of automatic
0541  *     (`{}`) and manual indexed (`{1}`) replacement fields.
0542  * \li \ref client_errc::format_arg_not_found if an argument referenced by `format_str` isn't present
0543  *     in `args` (there aren't enough arguments or a named argument is not found).
0544  */
0545 template <BOOST_MYSQL_FORMATTABLE... Formattable>
0546 std::string format_sql(format_options opts, constant_string_view format_str, Formattable&&... args);
0547 
0548 /**
0549  * \copydoc format_sql
0550  * \details
0551  * \n
0552  * This overload allows using named arguments.
0553  */
0554 BOOST_MYSQL_DECL
0555 std::string format_sql(
0556     format_options opts,
0557     constant_string_view format_str,
0558     std::initializer_list<format_arg> args
0559 );
0560 
0561 }  // namespace mysql
0562 }  // namespace boost
0563 
0564 #include <boost/mysql/impl/format_sql.hpp>
0565 #ifdef BOOST_MYSQL_HEADER_ONLY
0566 #include <boost/mysql/impl/format_sql.ipp>
0567 #endif
0568 
0569 #endif