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