libpqxx
The C++ client library for PostgreSQL
conversions.hxx
Go to the documentation of this file.
1 #ifndef PQXX_INTERNAL_CONVERSIONS_HXX
2 #define PQXX_INTERNAL_CONVERSIONS_HXX
3 
4 #include <array>
5 #include <concepts>
6 #include <cstring>
7 #include <map>
8 #include <memory>
9 #include <numeric>
10 #include <optional>
11 #include <span>
12 #include <type_traits>
13 #include <variant>
14 
15 #include "pqxx/encoding_group.hxx"
16 #include "pqxx/strconv.hxx"
17 
18 
19 /* Internal helpers for string conversion, and conversion implementations.
20  *
21  * Do not include this header directly. The libpqxx headers do it for you.
22  */
23 namespace pqxx::internal
24 {
26 PQXX_PURE PQXX_HOT inline constexpr char number_to_digit(int i) noexcept
27 {
28  PQXX_ASSUME(i >= 0);
29  PQXX_ASSUME(i <= 9);
30  return static_cast<char>(i + '0');
31 }
32 
33 
35 
37 PQXX_PURE PQXX_HOT inline constexpr int digit_to_number(char c) noexcept
38 {
39  PQXX_ASSUME(c >= '0');
40  PQXX_ASSUME(c <= '9');
41  return c - '0';
42 }
43 
44 
46 
49 PQXX_LIBEXPORT PQXX_COLD std::string
50 state_buffer_overrun(int have_bytes, int need_bytes);
51 
52 
53 template<typename HAVE, typename NEED>
54 PQXX_INLINE_COV PQXX_COLD inline std::string
55 state_buffer_overrun(HAVE have_bytes, NEED need_bytes)
56 {
57  return state_buffer_overrun(
58  static_cast<int>(have_bytes), static_cast<int>(need_bytes));
59 }
60 
61 
63 [[noreturn]] PQXX_COLD PQXX_LIBEXPORT void
64 throw_null_conversion(std::string const &type, sl);
65 
66 
68 [[noreturn]] PQXX_COLD PQXX_LIBEXPORT void
69 throw_null_conversion(std::string_view type, sl);
70 
71 
73 
82 template<pqxx::internal::char_type CHAR_TYPE>
84 {
85  static constexpr std::size_t
86  size_buffer(CHAR_TYPE const &) noexcept = delete;
87 
88  static constexpr std::string_view
89  to_buf(std::span<char>, CHAR_TYPE const &, ctx = {}) noexcept = delete;
90 
91  static CHAR_TYPE from_string(std::string_view, ctx = {}) = delete;
92 };
93 
94 
95 template<std::floating_point T>
96 PQXX_LIBEXPORT extern std::string to_string_float(T, ctx = {});
97 
98 
100 template<typename T>
101 [[deprecated("into_buf() is no longer part of the string conversion API.")]]
102 inline char *
103 generic_into_buf(char *begin, char *end, T const &value, ctx c = {})
104 {
105  zview text{to_buf({begin, end}, value, c)};
106  auto const space{end - begin};
107  // Include the trailing zero.
108  auto const len = std::size(text) + 1;
109  if (std::cmp_greater(len, space))
110  throw conversion_overrun{
111  std::format("Not enough buffer space to insert {}.", name_type<T>()) +
112  state_buffer_overrun(space, len),
113  c.loc};
114  std::memmove(begin, std::data(text), len);
115  return begin + len;
116 }
117 
118 
120 template<typename T>
121 [[deprecated("into_buf() is no longer part of the string conversion API.")]]
122 inline std::size_t
123 generic_into_buf(std::span<char> buf, T const &value, ctx c = {})
124 {
125  auto const begin{std::data(buf)};
126  zview text{to_buf(buf, value, c)};
127  auto const space{std::size(buf)};
128  // Include the trailing zero.
129  auto const len = std::size(text) + 1;
130  if (std::cmp_greater(len, space))
131  throw conversion_overrun{
132  std::format("Not enough buffer space to insert {}. ", name_type<T>()) +
133  state_buffer_overrun(space, len),
134  c.loc};
135  std::memmove(begin, std::data(text), len);
136  return len;
137 }
138 
139 
141 
148 template<std::floating_point T> struct float_string_traits
149 {
150  PQXX_LIBEXPORT PQXX_HOT static T
151  from_string(std::string_view text, ctx = {});
152 
153  PQXX_LIBEXPORT PQXX_HOT static std::string_view
154  to_buf(std::span<char> buf, T const &value, ctx c = {});
155 
156  // Return a nonnegative integral value's number of decimal digits.
157  PQXX_HOT static constexpr std::size_t digits10(std::size_t value) noexcept
158  {
159  if (value < 10)
160  return 1;
161  else
162  return 1 + digits10(value / 10);
163  }
164 
165  PQXX_HOT PQXX_INLINE_COV static constexpr std::size_t
166  size_buffer(T const &) noexcept
167  {
168  using lims = std::numeric_limits<T>;
169  // See #328 for a detailed discussion on the maximum number of digits.
170  //
171  // In a nutshell: for the big cases, the scientific notation is always
172  // the shortest one, and therefore the one that to_chars will pick.
173  //
174  // So... How long can the scientific notation get? 1 (for sign) + 1 (for
175  // decimal point) + 1 (for 'e') + 1 (for exponent sign) + max_digits10 +
176  // max number of digits in the exponent + 1 (terminating zero).
177  //
178  // What's the max number of digits in the exponent? It's the max number of
179  // digits out of the most negative exponent and the most positive one.
180  //
181  // The longest positive exponent is easy: 1 + ceil(log10(max_exponent10)).
182  // (The extra 1 is because 10^n takes up 1 + n digits, not n.)
183  //
184  // The longest negative exponent is a bit harder: min_exponent10 gives us
185  // the smallest power of 10 which a normalised version of T can represent.
186  // But the smallest denormalised power of 10 that T can represent is
187  // another max_digits10 powers of 10 below that. It also needs room for a
188  // a minus sign.
189  //
190  // All this stuff messes with my head a bit because it's on the order of
191  // log10(log10(n)). It's easy to get the number of logs wrong.
192  auto const max_pos_exp{digits10(lims::max_exponent10)};
193  // Really want std::abs(lims::min_exponent10), but MSVC 2017 apparently has
194  // problems with std::abs. So we use -lims::min_exponent10 instead.
195  auto const max_neg_exp{
196  digits10(lims::max_digits10 - lims::min_exponent10)};
197  return 1 + // Sign.
198  1 + // Decimal point.
199  std::numeric_limits<T>::max_digits10 + // Mantissa digits.
200  1 + // Exponent "e".
201  1 + // Exponent sign.
202  // Spell this weirdly to stop Windows compilers from reading this as
203  // a call to their "max" macro when NOMINMAX is not defined.
204  (std::max)(max_pos_exp, max_neg_exp); // Exponent digits.
205  }
206 };
207 
209 
216 template<pqxx::internal::integer T> struct integer_string_traits
217 {
218  PQXX_LIBEXPORT PQXX_HOT static T
219  from_string(std::string_view text, ctx = {});
220  PQXX_LIBEXPORT PQXX_HOT static std::string_view
221  to_buf(std::span<char> buf, T const &value, ctx c = {});
222 
223  PQXX_INLINE_ONLY PQXX_HOT static constexpr std::size_t
224  size_buffer(T const &) noexcept
225  {
230  return std::is_signed_v<T> + std::numeric_limits<T>::digits10 + 1;
231  }
232 };
233 } // namespace pqxx::internal
234 
235 namespace pqxx
236 {
238 
241 template<typename T>
242  requires std::is_arithmetic_v<T>
243 struct nullness<T> final : no_null<T>
244 {};
245 
246 
247 template<pqxx::internal::integer T>
248 inline constexpr bool is_unquoted_safe<T>{true};
249 template<std::floating_point T>
250 inline constexpr bool is_unquoted_safe<T>{true};
251 
252 #define PQXX_SPECIALIZE_INT_TRAIT(typ) \
253  template<> \
254  struct string_traits<typ> final \
255  : pqxx::internal::integer_string_traits<typ> \
256  {}
257 
265 PQXX_SPECIALIZE_INT_TRAIT(unsigned long long);
266 
267 #undef PQXX_SPECIALIZE_INT_TRAIT
268 
269 template<>
271 {};
272 template<>
273 struct string_traits<double> final
275 {};
276 template<>
277 struct string_traits<long double> final
279 {};
280 
281 
282 template<> struct string_traits<bool> final
283 {
284  PQXX_LIBEXPORT PQXX_HOT static bool
285  from_string(std::string_view text, ctx c = {});
286 
287  PQXX_PURE PQXX_HOT static constexpr std::string_view
288  to_buf(std::span<char>, bool const &value, ctx = {}) noexcept
289  {
290  return value ? "true" : "false";
291  }
292 
293  PQXX_PURE PQXX_HOT static constexpr std::size_t
294  size_buffer(bool const &) noexcept
295  {
296  return 6;
297  }
298 };
299 
300 
301 template<> inline constexpr bool is_unquoted_safe<bool>{true};
302 
303 
304 template<typename T> struct nullness<std::optional<T>> final
305 {
306  static constexpr bool has_null = true;
308  static constexpr bool always_null = pqxx::always_null<T>();
309  [[nodiscard]] PQXX_PURE PQXX_HOT static constexpr bool
310  is_null(std::optional<T> const &v) noexcept
311  {
312  return ((not v.has_value()) or pqxx::is_null(*v));
313  }
314  [[nodiscard]] PQXX_PURE PQXX_HOT static constexpr std::optional<T>
315  null() noexcept
316  {
317  return {};
318  }
319 };
320 
321 
322 template<typename T>
323 inline constexpr format param_format(std::optional<T> const &value)
324 {
325  return param_format(*value);
326 }
327 
328 
329 template<typename T> struct string_traits<std::optional<T>> final
330 {
331  static std::string_view
332  to_buf(std::span<char> buf, std::optional<T> const &value, ctx c = {})
333  {
334  if (pqxx::is_null(value))
335  return {};
336  else
337  // (No need to check: if the optional were empty, it'd be null.)
338  // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
339  return pqxx::to_buf(buf, *value, c);
340  }
341 
342  static std::optional<T> from_string(std::string_view text, ctx c = {})
343  {
344  return std::optional<T>{std::in_place, pqxx::from_string<T>(text, c)};
345  }
346 
347  static std::size_t size_buffer(std::optional<T> const &value) noexcept
348  {
349  if (pqxx::is_null(value))
350  return 0;
351  else
352  // (No need to check: if the optional were empty, it'd be null.)
353  // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
354  return pqxx::size_buffer(value.value());
355  }
356 };
357 
358 
359 template<typename T>
360 inline constexpr bool is_unquoted_safe<std::optional<T>>{is_unquoted_safe<T>};
361 
362 
363 template<typename... T> struct nullness<std::variant<T...>> final
364 {
365  static constexpr bool has_null = (pqxx::has_null<T>() or ...);
366  static constexpr bool always_null = (pqxx::always_null<T>() and ...);
367  [[nodiscard]] PQXX_PURE static constexpr bool
368  is_null(std::variant<T...> const &value) noexcept
369  {
370  return value.valueless_by_exception() or
371  std::visit(
372  [](auto const &i) noexcept {
373  return nullness<std::remove_cvref_t<decltype(i)>>::is_null(i);
374  },
375  value);
376  }
377 
378  // We don't support `null()` for `std::variant`.
382  static constexpr std::variant<T...> null() = delete;
383 };
384 
385 
386 template<typename... T> struct string_traits<std::variant<T...>> final
387 {
388  static std::string_view
389  to_buf(std::span<char> buf, std::variant<T...> const &value, ctx c = {})
390  {
391  return std::visit(
392  [buf, c](auto const &i) {
393  using field_t = std::remove_cvref_t<decltype(i)>;
394  return pqxx::to_buf<field_t>(buf, i, c);
395  },
396  value);
397  }
398  static std::size_t size_buffer(std::variant<T...> const &value) noexcept
399  {
400  if (pqxx::is_null(value))
401  return 0;
402  else
403  return std::visit(
404  [](auto const &i) noexcept { return pqxx::size_buffer(i); }, value);
405  }
406 
411  static std::variant<T...> from_string(std::string_view, ctx = {}) = delete;
412 };
413 
414 
415 template<typename... Args>
416 inline constexpr format param_format(std::variant<Args...> const &value)
417 {
418  return std::visit([](auto &v) { return param_format(v); }, value);
419 }
420 
421 
422 template<typename... T>
423 inline constexpr bool is_unquoted_safe<std::variant<T...>>{
424  (is_unquoted_safe<T> and ...)};
425 
426 
427 template<typename T>
428 inline T from_string(std::stringstream const &text, ctx c = {})
429 {
430  return from_string<T>(text.str(), c);
431 }
432 
433 
434 template<> struct string_traits<std::nullptr_t> final
435 {
436  [[deprecated("Do not convert nulls.")]] static constexpr zview
437  to_buf(std::span<char>, std::nullptr_t const &, ctx = {}) noexcept
438  {
439  return {};
440  }
441 
442  [[deprecated("Do not convert nulls.")]] static constexpr std::size_t
443  size_buffer(std::nullptr_t = nullptr) noexcept
444  {
445  return 0;
446  }
447  static std::nullptr_t from_string(std::string_view, ctx = {}) = delete;
448 };
449 
450 
451 template<> struct string_traits<std::nullopt_t> final
452 {
453  [[deprecated("Do not convert nulls.")]] static constexpr zview
454  to_buf(char *, char *, std::nullopt_t const &) noexcept
455  {
456  return {};
457  }
458 
459  [[deprecated("Do not convert nulls.")]] static constexpr std::size_t
460  size_buffer(std::nullopt_t) noexcept
461  {
462  return 0;
463  }
464  static std::nullopt_t from_string(std::string_view, ctx = {}) = delete;
465 };
466 
467 
468 template<> struct string_traits<std::monostate> final
469 {
470  [[deprecated("Do not convert nulls.")]] static constexpr zview
471  to_buf(char *, char *, std::monostate const &) noexcept
472  {
473  return {};
474  }
475 
476  [[deprecated("Do not convert nulls.")]] static constexpr std::size_t
477  size_buffer(std::monostate) noexcept
478  {
479  return 0;
480  }
481  [[deprecated("Do not convert nulls.")]] static std::monostate
482  from_string(std::string_view, ctx = {}) = delete;
483 };
484 
485 
486 template<> inline constexpr bool is_unquoted_safe<std::nullptr_t>{true};
487 
488 
489 template<> struct nullness<char const *> final
490 {
491  static constexpr bool has_null = true;
492  static constexpr bool always_null = false;
493  [[nodiscard]] PQXX_PURE PQXX_ZARGS static constexpr bool
494  is_null(char const *t) noexcept
495  {
496  return t == nullptr;
497  }
498  [[nodiscard]] PQXX_PURE static constexpr char const *null() noexcept
499  {
500  return nullptr;
501  }
502 };
503 
504 
506 
515 template<> struct string_traits<char const *> final
516 {
517  static char const *from_string(std::string_view text, ctx = {}) = delete;
518 
519  constexpr PQXX_ZARGS static std::string_view
520  to_buf(std::span<char>, char const *const &value, ctx = {}) noexcept
521  {
522  return value;
523  }
524 
525  PQXX_ZARGS static constexpr std::size_t
526  size_buffer(char const *value) noexcept
527  {
528  if (pqxx::is_null(value))
529  return 0;
530  else
531  // std::char_traits::length() is like std::strlen(), but constexpr.
532  return std::char_traits<char>::length(value);
533  }
534 };
535 
536 
537 template<> struct nullness<char *> final
538 {
539  static constexpr bool has_null = true;
540  static constexpr bool always_null = false;
541  [[nodiscard]] PQXX_PURE static constexpr bool is_null(char const *t) noexcept
542  {
543  return t == nullptr;
544  }
545  [[nodiscard]] PQXX_PURE static constexpr char *null() { return nullptr; }
546 };
547 
548 
550 
559 template<> struct string_traits<char *> final
560 {
561  static std::string_view
562  to_buf(std::span<char> buf, char *const &value, ctx c = {})
563  {
564  return pqxx::to_buf<char const *>(buf, value, c);
565  }
566  static std::size_t size_buffer(char *const &value) noexcept
567  {
568  if (pqxx::is_null(value))
569  return 0;
570  else
571  return pqxx::size_buffer(const_cast<char const *>(value));
572  }
573 
574  static char *from_string(std::string_view, ctx = {}) = delete;
575 };
576 
577 
578 template<std::size_t N> struct nullness<char[N]> final : no_null<char[N]>
579 {};
580 
581 
583 
586 template<std::size_t N> struct string_traits<char[N]> final
587 {
588  static constexpr zview
589  to_buf(std::span<char>, char const (&value)[N], ctx = {}) noexcept
590  {
591  return zview{value, N - 1};
592  }
593 
594  static constexpr std::size_t size_buffer(char const (&)[N]) noexcept
595  {
596  return N;
597  }
598 
600  static void from_string(std::string_view, ctx = {}) = delete;
601 };
602 
603 
604 template<> struct nullness<std::string> final : no_null<std::string>
605 {};
606 
607 
608 template<> struct string_traits<std::string> final
609 {
610  PQXX_INLINE_ONLY static std::string
611  from_string(std::string_view text, ctx = {})
612  {
613  return std::string{text};
614  }
615 
616  PQXX_INLINE_ONLY static std::string_view
617  to_buf(std::span<char>, std::string const &value, ctx = {})
618  {
619  return {std::data(value), std::size(value)};
620  }
621 
622  PQXX_INLINE_ONLY static constexpr std::size_t
623  size_buffer(std::string const &value) noexcept
624  {
625  return std::size(value);
626  }
627 };
628 
629 
631 
635 template<> struct nullness<std::string_view> final : no_null<std::string_view>
636 {};
637 
638 
640 
645 template<> struct string_traits<std::string_view> final
646 {
647  PQXX_INLINE_ONLY static constexpr std::size_t
648  size_buffer(std::string_view const &value) noexcept
649  {
650  return std::size(value);
651  }
652 
653  PQXX_INLINE_ONLY static std::string_view
654  to_buf(std::span<char>, std::string_view const &value, ctx = {})
655  {
656  return value;
657  }
658 
659  PQXX_INLINE_ONLY static std::string_view
660  from_string(std::string_view value, ctx = {})
661  {
662  return value;
663  }
664 };
665 
666 
667 template<> struct nullness<zview> final : no_null<zview>
668 {};
669 
670 
672 template<> struct string_traits<zview> final
673 {
674  PQXX_INLINE_ONLY static constexpr std::size_t
675  size_buffer(std::string_view const &value) noexcept
676  {
677  return std::size(value);
678  }
679 
680  static constexpr zview to_buf(std::span<char>, zview const &value, ctx = {})
681  {
682  return value;
683  }
684 
686 
690  static zview from_string(std::string_view, ctx = {}) = delete;
691 };
692 
693 
694 template<>
695 struct nullness<std::stringstream> final : no_null<std::stringstream>
696 {};
697 
698 
699 template<> struct string_traits<std::stringstream> final
700 {
701  static std::size_t size_buffer(std::stringstream const &) = delete;
702 
703  static std::stringstream from_string(std::string_view text, ctx = {})
704  {
705  std::stringstream stream;
706  stream.write(text.data(), std::streamsize(std::size(text)));
707  return stream;
708  }
709 
710  static std::string_view
711  to_buf(std::span<char>, std::stringstream const &, ctx = {}) = delete;
712 };
713 
714 
715 template<>
716 struct nullness<std::nullptr_t> final : all_null<std::nullptr_t, nullptr>
717 {};
718 
719 template<>
720 struct nullness<std::nullopt_t> final : all_null<std::nullopt_t, std::nullopt>
721 {};
722 
723 template<>
724 struct nullness<std::monostate> final
725  : all_null<std::monostate, std::monostate{}>
726 {};
727 
728 
729 template<typename T> struct nullness<std::unique_ptr<T>> final
730 {
731  static constexpr bool has_null = true;
732  static constexpr bool always_null = false;
733  [[nodiscard]] PQXX_PURE static constexpr bool
734  is_null(std::unique_ptr<T> const &t) noexcept
735  {
736  return not t or pqxx::is_null(*t);
737  }
738  [[nodiscard]] PQXX_PURE static constexpr std::unique_ptr<T> null() noexcept
739  {
740  return {};
741  }
742 };
743 
744 
745 template<typename T, typename... Args>
746 struct string_traits<std::unique_ptr<T, Args...>> final
747 {
748  static std::unique_ptr<T> from_string(std::string_view text, ctx c = {})
749  {
750  return std::make_unique<T>(pqxx::from_string<T>(text, c));
751  }
752 
753  static std::string_view to_buf(
754  std::span<char> buf, std::unique_ptr<T, Args...> const &value, ctx c = {})
755  {
756  if (not value)
757  internal::throw_null_conversion(name_type<std::unique_ptr<T>>(), c.loc);
758  return pqxx::to_buf(buf, *value, c);
759  }
760 
761  static std::size_t
762  size_buffer(std::unique_ptr<T, Args...> const &value) noexcept
763  {
764  if (pqxx::is_null(value))
765  return 0;
766  else
767  return pqxx::size_buffer(*value.get());
768  }
769 };
770 
771 
772 template<typename T, typename... Args>
773 inline format param_format(std::unique_ptr<T, Args...> const &value)
774 {
775  return param_format(*value);
776 }
777 
778 
779 template<typename T, typename... Args>
780 inline constexpr bool is_unquoted_safe<std::unique_ptr<T, Args...>>{
782 
783 
784 template<typename T> struct nullness<std::shared_ptr<T>> final
785 {
786  static constexpr bool has_null = true;
787  static constexpr bool always_null = false;
788  [[nodiscard]] PQXX_PURE static constexpr bool
789  is_null(std::shared_ptr<T> const &t) noexcept
790  {
791  return not t or pqxx::is_null(*t);
792  }
793  [[nodiscard]] PQXX_PURE static constexpr std::shared_ptr<T> null() noexcept
794  {
795  return {};
796  }
797 };
798 
799 
800 template<typename T> struct string_traits<std::shared_ptr<T>> final
801 {
802  static std::shared_ptr<T> from_string(std::string_view text, ctx c = {})
803  {
804  return std::make_shared<T>(pqxx::from_string<T>(text, c));
805  }
806 
807  static std::string_view
808  to_buf(std::span<char> buf, std::shared_ptr<T> const &value, ctx c = {})
809  {
810  if (not value)
811  internal::throw_null_conversion(name_type<std::shared_ptr<T>>(), c.loc);
812  return pqxx::to_buf(buf, *value, c);
813  }
814  static std::size_t size_buffer(std::shared_ptr<T> const &value) noexcept
815  {
816  if (pqxx::is_null(value))
817  return 0;
818  else
819  return pqxx::size_buffer(*value);
820  }
821 };
822 
823 
824 template<typename T> format param_format(std::shared_ptr<T> const &value)
825 {
826  return param_format(*value);
827 }
828 
829 
830 template<typename T>
831 inline constexpr bool is_unquoted_safe<std::shared_ptr<T>>{
833 
834 
835 template<binary DATA> struct nullness<DATA> final : no_null<DATA>
836 {};
837 
838 
839 template<binary DATA> struct string_traits<DATA> final
840 {
841  static std::size_t size_buffer(DATA const &value) noexcept
842  {
843  return internal::size_esc_bin(std::size(value));
844  }
845 
846  static std::string_view
847  to_buf(std::span<char> buf, DATA const &value, ctx c = {})
848  {
849  // Budget for this type is precise.
850  auto const budget{size_buffer(value)};
851  if (std::cmp_less(std::size(buf), budget))
852  throw conversion_overrun{
853  "Not enough buffer space to escape binary data.", c.loc};
854  internal::esc_bin(value, buf);
855  // The budget included a terminating zero, which we do not include in the
856  // view.
857  return {std::data(buf), budget - 1};
858  }
859 
861  static DATA from_string(std::string_view text, ctx c = {})
862  {
863  auto const size{pqxx::internal::size_unesc_bin(std::size(text))};
864  DATA buf{};
865  if constexpr (requires { buf.resize(std::size_t{}); })
866  {
867  // Make `buf` allocate the number of bytes we need to store.
868  buf.resize(size);
869  }
870  else
871  {
872  // There's no suitable `DATA::resize()`. But perhaps the caller has
873  // ensured that `DATA` is a type that inherently has the right size.
874  // Might a `std::array<std::byte, ...>` for instance.
875  if (std::size(buf) != size)
876  throw conversion_error{
877  std::format(
878  "Can't convert binary data from SQL text to {}: I don't know how "
879  "to "
880  "resize that type.",
881  name_type<DATA>()),
882  c.loc};
883  }
884 
885  pqxx::internal::unesc_bin(text, buf, c.loc);
886  return buf;
887  }
888 };
889 } // namespace pqxx
890 
891 
892 namespace pqxx::internal
893 {
894 template<nonbinary_range TYPE>
895 inline std::size_t array_into_buf(
896  std::span<char> buf, TYPE const &value, std::size_t budget, ctx c = {});
897 
898 
900 
903 template<typename T> struct nonbinary_range_traits
904 {
905  using elt_type = std::remove_cvref_t<value_type<T>>;
907  static constexpr zview s_null{"NULL"};
908 
909  static std::size_t size_buffer(T const &value) noexcept
910  {
911  if constexpr (is_unquoted_safe<elt_type>)
912  return 3 + std::accumulate(
913  std::begin(value), std::end(value), std::size_t{},
914  [](std::size_t acc, elt_type const &elt) {
915  // Add one extra byte for the separator
916  return acc + (pqxx::is_null(elt) ?
917  std::size(s_null) :
918  elt_traits::size_buffer(elt)) + 1;
919  });
920  else
921  return 3 + std::accumulate(
922  std::begin(value), std::end(value), std::size_t{},
923  [](std::size_t acc, elt_type const &elt) {
924  // Opening and closing quotes, plus worst-case escaping,
925  // plus one byte for the separator.
926  std::size_t const elt_size{
927  pqxx::is_null(elt) ? std::size(s_null) :
929  return acc + 2 * elt_size + 3;
930  });
931  }
932 
933  static std::string_view
934  to_buf(std::span<char> buf, T const &value, ctx c = {})
935  {
936  auto const sz{
937  pqxx::internal::array_into_buf(buf, value, size_buffer(value), c)};
938  return {std::data(buf), sz};
939  }
940 };
941 } // namespace pqxx::internal
942 
943 
944 namespace pqxx
945 {
946 template<nonbinary_range T> struct nullness<T> final : no_null<T>
947 {};
948 
949 
951 
956 template<nonbinary_range T>
958 {};
959 
960 
962 template<nonbinary_range T> inline constexpr format param_format(T const &)
963 {
964  return format::text;
965 }
966 
967 
969 template<binary T> inline constexpr format param_format(T const &)
970 {
971  return format::binary;
972 }
973 
974 
975 template<nonbinary_range T> inline constexpr bool is_sql_array<T>{true};
976 
977 
978 template<typename TYPE>
979 PQXX_INLINE_COV inline std::string to_string(TYPE const &value, ctx c)
980 {
981  if (is_null(value))
982  throw conversion_error{
983  std::format("Attempt to convert null to a string.", name_type<TYPE>()),
984  c.loc};
985 
986  if constexpr (pqxx::always_null<TYPE>())
987  {
988  // Have to separate out this case: some functions in the "regular" code
989  // may not exist in the "always null" case.
991  // C++23: The return may not be needed when std::unreachable is available.
992  return {};
993  }
994  else
995  {
996  std::string buf;
997  // We can't just reserve() space; modifying the terminating zero leads to
998  // undefined behaviour.
999  buf.resize(pqxx::size_buffer(value));
1000  std::size_t const stop{pqxx::into_buf(buf, value, c)};
1001  buf.resize(stop);
1002  return buf;
1003  }
1004 }
1005 
1006 
1007 template<> inline std::string to_string(float const &value, ctx c)
1008 {
1009  return pqxx::internal::to_string_float(value, c);
1010 }
1011 template<> inline std::string to_string(double const &value, ctx c)
1012 {
1013  return pqxx::internal::to_string_float(value, c);
1014 }
1015 template<> inline std::string to_string(long double const &value, ctx c)
1016 {
1017  return pqxx::internal::to_string_float(value, c);
1018 }
1019 
1020 // clang-tidy rule bug:
1021 // NOLINTNEXTLINE(misc-unused-parameters)
1022 template<> inline std::string to_string(std::stringstream const &value, ctx)
1023 {
1024  return value.str();
1025 }
1026 
1027 
1028 template<typename T>
1029 inline void into_string(T const &value, std::string &out, ctx c = {})
1030 {
1031  if (is_null(value))
1032  throw conversion_error{
1033  std::format("Attempt to convert null {} to a string.", name_type<T>()),
1034  c.loc};
1035 
1036  // We can't just reserve() data; modifying the terminating zero leads to
1037  // undefined behaviour.
1038  out.resize(size_buffer(value));
1039  auto const data{out.data()};
1040  auto const end{into_buf({data, std::size(out)}, value, c)};
1041  out.resize(static_cast<std::size_t>(end - data));
1042 }
1043 } // namespace pqxx
1044 #endif
Marker-type wrapper: zero-terminated std::string_view.
Definition: zview.hxx:55
#define PQXX_SPECIALIZE_INT_TRAIT(typ)
Definition: conversions.hxx:252
Value conversion failed, e.g. when converting "Hello" to int.
Definition: except.hxx:612
#define PQXX_ZARGS
Definition: header-pre.hxx:144
#define PQXX_COLD
Definition: header-pre.hxx:80
#define PQXX_LIBEXPORT
Definition: header-pre.hxx:225
#define PQXX_PURE
Definition: header-pre.hxx:64
#define PQXX_ASSUME(condition)
Definition: header-pre.hxx:247
#define PQXX_HOT
Definition: header-pre.hxx:72
#define PQXX_INLINE_COV
Don't generate out-of-line version of inline function for coverage runs.
Definition: header-pre.hxx:106
#define PQXX_INLINE_ONLY
Definition: header-pre.hxx:91
Private namespace for libpqxx's internal use; do not access.
Definition: connection.cxx:333
std::string to_string_float(T value, [[maybe_unused]] ctx c)
Floating-point implementations for pqxx::to_string().
Definition: strconv.cxx:327
PQXX_PURE constexpr PQXX_HOT int digit_to_number(char c) noexcept
Compute numeric value of given textual digit (assuming that it is a digit).
Definition: conversions.hxx:37
char * generic_into_buf(char *begin, char *end, T const &value, ctx c={})
Generic implementation for into_buf(), on top of to_buf().
Definition: conversions.hxx:103
std::string state_buffer_overrun(int have_bytes, int need_bytes)
Summarize buffer overrun.
Definition: strconv.cxx:156
void unesc_bin(std::string_view escaped_data, std::span< std::byte > buffer, sl loc)
Reconstitute binary data from its escaped version.
Definition: util.cxx:194
constexpr PQXX_PURE std::size_t size_esc_bin(std::size_t binary_bytes) noexcept
Compute buffer size needed to escape binary data for use as a BYTEA.
Definition: util.hxx:493
void throw_null_conversion(std::string const &type, sl loc)
Throw exception for attempt to convert SQL NULL to given type.
Definition: strconv.cxx:142
PQXX_PURE constexpr PQXX_HOT char number_to_digit(int i) noexcept
Convert a number in [0, 9] to its ASCII digit.
Definition: conversions.hxx:26
PQXX_INLINE_COV std::size_t array_into_buf(std::span< char > buf, TYPE const &value, std::size_t budget, ctx c)
Write an SQL array representation into buf.
Definition: array-composite.hxx:419
constexpr PQXX_PURE std::size_t size_unesc_bin(std::size_t escaped_bytes) noexcept
Compute binary size from the size of its escaped version.
Definition: util.hxx:505
void esc_bin(bytes_view binary_data, std::span< char > buffer) noexcept
Hex-escape binary data into a buffer.
Definition: util.cxx:159
The home of all libpqxx classes, functions, templates, etc.
Definition: array.cxx:26
std::string_view to_buf(std::span< char > buf, TYPE const &value, ctx c={})
Represent value as SQL text, optionally using buf as storage.
Definition: strconv.hxx:430
constexpr bool is_sql_array< T >
Definition: conversions.hxx:975
constexpr bool has_null() noexcept
Does TYPE have one or more inherent null values?
Definition: strconv.hxx:744
std::source_location sl
Convenience alias for std::source_location. It's just too long.
Definition: types.hxx:38
constexpr format param_format(std::optional< T > const &value)
Definition: conversions.hxx:323
constexpr std::string_view name_type() noexcept
Return human-readable name for TYPE.
Definition: types.hxx:277
T from_string(field const &value, ctx c={})
Convert a field's value to type T.
Definition: field.hxx:831
PQXX_LIBEXPORT std::string to_string(field_ref const &value, ctx)
Convert a field_ref to a string.
Definition: field.hxx:891
constexpr bool is_unquoted_safe< T >
Definition: conversions.hxx:248
constexpr std::size_t size_buffer(TYPE const &...value) noexcept
Estimate how much buffer space is needed to represent values as a string.
Definition: strconv.hxx:399
constexpr bool is_null(TYPE const &value) noexcept
Is value a null?
Definition: strconv.hxx:764
requires(pqxx::internal::to_buf_7< TYPE > or pqxx::internal::to_buf_8< TYPE >) const eval bool supports_to_buf_8()
Is the libpqxx 8 version of to_buf() supported for TYPE?
Definition: strconv.hxx:417
std::size_t into_buf(std::span< char > buf, TYPE const &value, ctx c={})
Write an SQL representation of value into buf.
Definition: strconv.hxx:454
constexpr bool is_unquoted_safe< bool >
Definition: conversions.hxx:301
conversion_context const & ctx
Convenience alias: const reference to a pqxx::conversion_context.
Definition: strconv.hxx:201
constexpr bool always_null() noexcept
Is a value of TYPE always null?
Definition: strconv.hxx:755
constexpr bool is_unquoted_safe
Can we use this type in arrays and composite types without quoting them?
Definition: strconv.hxx:812
format
Format code: is data text or binary?
Definition: types.hxx:121
void into_string(T const &value, std::string &out, ctx c={})
Definition: conversions.hxx:1029
Nullness traits describing a type whose values are always null.
Definition: strconv.hxx:133
Deliberately nonfunctional conversion traits for char types.
Definition: conversions.hxx:84
static constexpr std::size_t size_buffer(CHAR_TYPE const &) noexcept=delete
static constexpr std::string_view to_buf(std::span< char >, CHAR_TYPE const &, ctx={}) noexcept=delete
static CHAR_TYPE from_string(std::string_view, ctx={})=delete
String traits for builtin floating-point types.
Definition: conversions.hxx:149
static constexpr PQXX_HOT std::size_t digits10(std::size_t value) noexcept
Definition: conversions.hxx:157
PQXX_LIBEXPORT static PQXX_HOT T from_string(std::string_view text, ctx={})
Definition: strconv.cxx:345
PQXX_HOT static constexpr PQXX_INLINE_COV std::size_t size_buffer(T const &) noexcept
Definition: conversions.hxx:166
PQXX_LIBEXPORT static PQXX_HOT std::string_view to_buf(std::span< char > buf, T const &value, ctx c={})
Definition: strconv.cxx:357
String traits for builtin integer types.
Definition: conversions.hxx:217
PQXX_INLINE_ONLY static constexpr PQXX_HOT std::size_t size_buffer(T const &) noexcept
Definition: conversions.hxx:224
PQXX_LIBEXPORT static PQXX_HOT T from_string(std::string_view text, ctx={})
Definition: strconv.cxx:390
PQXX_LIBEXPORT static PQXX_HOT std::string_view to_buf(std::span< char > buf, T const &value, ctx c={})
Definition: strconv.cxx:398
Base class for string_traits specialisations for nonbinary ranges.
Definition: conversions.hxx:904
std::remove_cvref_t< value_type< T > > elt_type
Definition: conversions.hxx:905
static std::string_view to_buf(std::span< char > buf, T const &value, ctx c={})
Definition: conversions.hxx:934
static std::size_t size_buffer(T const &value) noexcept
Definition: conversions.hxx:909
static constexpr zview s_null
Definition: conversions.hxx:907
Nullness traits describing a type which does not have a null value.
Definition: strconv.hxx:93
static constexpr PQXX_PURE bool is_null(char const *t) noexcept
Definition: conversions.hxx:541
PQXX_PURE static constexpr PQXX_ZARGS bool is_null(char const *t) noexcept
Definition: conversions.hxx:494
PQXX_PURE static constexpr PQXX_HOT bool is_null(std::optional< T > const &v) noexcept
Definition: conversions.hxx:310
static constexpr PQXX_PURE bool is_null(std::shared_ptr< T > const &t) noexcept
Definition: conversions.hxx:789
static constexpr PQXX_PURE bool is_null(std::unique_ptr< T > const &t) noexcept
Definition: conversions.hxx:734
Traits describing a type's "null value," if any.
Definition: strconv.hxx:70
static constexpr bool always_null
Is this type always null?
Definition: strconv.hxx:76
static PQXX_PURE bool is_null(TYPE const &value)
Is value a null?
static bool has_null
Does this type have a null value?
Definition: strconv.hxx:72
static std::string_view to_buf(std::span< char > buf, DATA const &value, ctx c={})
Definition: conversions.hxx:847
static DATA from_string(std::string_view text, ctx c={})
Convert a string to binary data.
Definition: conversions.hxx:861
static std::size_t size_buffer(DATA const &value) noexcept
Definition: conversions.hxx:841
PQXX_PURE static constexpr PQXX_HOT std::string_view to_buf(std::span< char >, bool const &value, ctx={}) noexcept
Definition: conversions.hxx:288
PQXX_PURE static constexpr PQXX_HOT std::size_t size_buffer(bool const &) noexcept
Definition: conversions.hxx:294
static std::size_t size_buffer(char *const &value) noexcept
Definition: conversions.hxx:566
static std::string_view to_buf(std::span< char > buf, char *const &value, ctx c={})
Definition: conversions.hxx:562
static char * from_string(std::string_view, ctx={})=delete
constexpr static PQXX_ZARGS std::string_view to_buf(std::span< char >, char const *const &value, ctx={}) noexcept
Definition: conversions.hxx:520
static constexpr PQXX_ZARGS std::size_t size_buffer(char const *value) noexcept
Definition: conversions.hxx:526
static char const * from_string(std::string_view text, ctx={})=delete
static constexpr zview to_buf(std::span< char >, char const (&value)[N], ctx={}) noexcept
Definition: conversions.hxx:589
static void from_string(std::string_view, ctx={})=delete
Don't allow conversion to this type.
static constexpr std::size_t size_buffer(char const (&)[N]) noexcept
Definition: conversions.hxx:594
static constexpr zview to_buf(char *, char *, std::monostate const &) noexcept
Definition: conversions.hxx:471
static constexpr std::size_t size_buffer(std::monostate) noexcept
Definition: conversions.hxx:477
static std::monostate from_string(std::string_view, ctx={})=delete
static constexpr zview to_buf(char *, char *, std::nullopt_t const &) noexcept
Definition: conversions.hxx:454
static std::nullopt_t from_string(std::string_view, ctx={})=delete
static constexpr std::size_t size_buffer(std::nullopt_t) noexcept
Definition: conversions.hxx:460
static constexpr std::size_t size_buffer(std::nullptr_t=nullptr) noexcept
Definition: conversions.hxx:443
static constexpr zview to_buf(std::span< char >, std::nullptr_t const &, ctx={}) noexcept
Definition: conversions.hxx:437
static std::nullptr_t from_string(std::string_view, ctx={})=delete
static std::optional< T > from_string(std::string_view text, ctx c={})
Definition: conversions.hxx:342
static std::size_t size_buffer(std::optional< T > const &value) noexcept
Definition: conversions.hxx:347
static std::string_view to_buf(std::span< char > buf, std::optional< T > const &value, ctx c={})
Definition: conversions.hxx:332
static std::shared_ptr< T > from_string(std::string_view text, ctx c={})
Definition: conversions.hxx:802
static std::size_t size_buffer(std::shared_ptr< T > const &value) noexcept
Definition: conversions.hxx:814
static std::string_view to_buf(std::span< char > buf, std::shared_ptr< T > const &value, ctx c={})
Definition: conversions.hxx:808
static PQXX_INLINE_ONLY std::string from_string(std::string_view text, ctx={})
Definition: conversions.hxx:611
static PQXX_INLINE_ONLY std::string_view to_buf(std::span< char >, std::string const &value, ctx={})
Definition: conversions.hxx:617
static constexpr PQXX_INLINE_ONLY std::size_t size_buffer(std::string const &value) noexcept
Definition: conversions.hxx:623
static PQXX_INLINE_ONLY std::string_view from_string(std::string_view value, ctx={})
Definition: conversions.hxx:660
static PQXX_INLINE_ONLY std::string_view to_buf(std::span< char >, std::string_view const &value, ctx={})
Definition: conversions.hxx:654
static constexpr PQXX_INLINE_ONLY std::size_t size_buffer(std::string_view const &value) noexcept
Definition: conversions.hxx:648
static std::stringstream from_string(std::string_view text, ctx={})
Definition: conversions.hxx:703
static std::size_t size_buffer(std::stringstream const &)=delete
static std::string_view to_buf(std::span< char >, std::stringstream const &, ctx={})=delete
static std::string_view to_buf(std::span< char > buf, std::unique_ptr< T, Args... > const &value, ctx c={})
Definition: conversions.hxx:753
static std::size_t size_buffer(std::unique_ptr< T, Args... > const &value) noexcept
Definition: conversions.hxx:762
static std::unique_ptr< T > from_string(std::string_view text, ctx c={})
Definition: conversions.hxx:748
static std::variant< T... > from_string(std::string_view, ctx={})=delete
static std::string_view to_buf(std::span< char > buf, std::variant< T... > const &value, ctx c={})
Definition: conversions.hxx:389
static std::size_t size_buffer(std::variant< T... > const &value) noexcept
Definition: conversions.hxx:398
static zview from_string(std::string_view, ctx={})=delete
Don't convert to this type. There may not be a terminating zero.
static constexpr zview to_buf(std::span< char >, zview const &value, ctx={})
Definition: conversions.hxx:680
static constexpr PQXX_INLINE_ONLY std::size_t size_buffer(std::string_view const &value) noexcept
Definition: conversions.hxx:675
Traits class for use in string conversions.
Definition: strconv.hxx:213
static std::size_t size_buffer(TYPE const &value) noexcept
Estimate how much buffer space is needed to represent value as SQL text.
static TYPE from_string(std::string_view text, ctx={})
Parse a string representation of a TYPE value.
Definition: time.cxx:198
#define PQXX_UNREACHABLE
Definition: util.hxx:51