![]() |
|
|||
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
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |
![]() ![]() |