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 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 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 std::string
50 state_buffer_overrun(int have_bytes, int need_bytes);
51 
52 
53 template<typename HAVE, typename NEED>
54 PQXX_INLINE_COV 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 static T from_string(std::string_view text, ctx = {});
151 
152  PQXX_LIBEXPORT static std::string_view
153  to_buf(std::span<char> buf, T const &value, ctx c = {});
154 
155  // Return a nonnegative integral value's number of decimal digits.
156  static constexpr std::size_t digits10(std::size_t value) noexcept
157  {
158  if (value < 10)
159  return 1;
160  else
161  return 1 + digits10(value / 10);
162  }
163 
164  PQXX_INLINE_COV static constexpr std::size_t size_buffer(T const &) noexcept
165  {
166  using lims = std::numeric_limits<T>;
167  // See #328 for a detailed discussion on the maximum number of digits.
168  //
169  // In a nutshell: for the big cases, the scientific notation is always
170  // the shortest one, and therefore the one that to_chars will pick.
171  //
172  // So... How long can the scientific notation get? 1 (for sign) + 1 (for
173  // decimal point) + 1 (for 'e') + 1 (for exponent sign) + max_digits10 +
174  // max number of digits in the exponent + 1 (terminating zero).
175  //
176  // What's the max number of digits in the exponent? It's the max number of
177  // digits out of the most negative exponent and the most positive one.
178  //
179  // The longest positive exponent is easy: 1 + ceil(log10(max_exponent10)).
180  // (The extra 1 is because 10^n takes up 1 + n digits, not n.)
181  //
182  // The longest negative exponent is a bit harder: min_exponent10 gives us
183  // the smallest power of 10 which a normalised version of T can represent.
184  // But the smallest denormalised power of 10 that T can represent is
185  // another max_digits10 powers of 10 below that. It also needs room for a
186  // a minus sign.
187  //
188  // All this stuff messes with my head a bit because it's on the order of
189  // log10(log10(n)). It's easy to get the number of logs wrong.
190  auto const max_pos_exp{digits10(lims::max_exponent10)};
191  // Really want std::abs(lims::min_exponent10), but MSVC 2017 apparently has
192  // problems with std::abs. So we use -lims::min_exponent10 instead.
193  auto const max_neg_exp{
194  digits10(lims::max_digits10 - lims::min_exponent10)};
195  return 1 + // Sign.
196  1 + // Decimal point.
197  std::numeric_limits<T>::max_digits10 + // Mantissa digits.
198  1 + // Exponent "e".
199  1 + // Exponent sign.
200  // Spell this weirdly to stop Windows compilers from reading this as
201  // a call to their "max" macro when NOMINMAX is not defined.
202  (std::max)(max_pos_exp, max_neg_exp); // Exponent digits.
203  }
204 };
205 
207 
214 template<pqxx::internal::integer T> struct integer_string_traits
215 {
216  PQXX_LIBEXPORT static T from_string(std::string_view text, ctx = {});
217  PQXX_LIBEXPORT static std::string_view
218  to_buf(std::span<char> buf, T const &value, ctx c = {});
219 
220  PQXX_INLINE_ONLY static constexpr std::size_t size_buffer(T const &) noexcept
221  {
226  return std::is_signed_v<T> + std::numeric_limits<T>::digits10 + 1;
227  }
228 };
229 } // namespace pqxx::internal
230 
231 namespace pqxx
232 {
234 
237 template<typename T>
238  requires std::is_arithmetic_v<T>
239 struct nullness<T> final : no_null<T>
240 {};
241 
242 
243 template<pqxx::internal::integer T>
244 inline constexpr bool is_unquoted_safe<T>{true};
245 template<std::floating_point T>
246 inline constexpr bool is_unquoted_safe<T>{true};
247 
248 #define PQXX_SPECIALIZE_INT_TRAIT(typ) \
249  template<> \
250  struct string_traits<typ> final \
251  : pqxx::internal::integer_string_traits<typ> \
252  {}
253 
261 PQXX_SPECIALIZE_INT_TRAIT(unsigned long long);
262 
263 #undef PQXX_SPECIALIZE_INT_TRAIT
264 
265 template<>
267 {};
268 template<>
269 struct string_traits<double> final
271 {};
272 template<>
273 struct string_traits<long double> final
275 {};
276 
277 
278 template<> struct string_traits<bool> final
279 {
280  PQXX_LIBEXPORT static bool from_string(std::string_view text, ctx c = {});
281 
282  static constexpr zview
283  to_buf(std::span<char>, bool const &value, ctx = {}) noexcept
284  {
285  return value ? "true"_zv : "false"_zv;
286  }
287 
288  static constexpr std::size_t size_buffer(bool const &) noexcept { return 5; }
289 };
290 
291 
292 template<> inline constexpr bool is_unquoted_safe<bool>{true};
293 
294 
295 template<typename T> struct nullness<std::optional<T>> final
296 {
297  static constexpr bool has_null = true;
299  static constexpr bool always_null = pqxx::always_null<T>();
300  [[nodiscard]] PQXX_PURE static constexpr bool
301  is_null(std::optional<T> const &v) noexcept
302  {
303  return ((not v.has_value()) or pqxx::is_null(*v));
304  }
305  [[nodiscard]] PQXX_PURE static constexpr std::optional<T> null() noexcept
306  {
307  return {};
308  }
309 };
310 
311 
312 template<typename T>
313 inline constexpr format param_format(std::optional<T> const &value)
314 {
315  return param_format(*value);
316 }
317 
318 
319 template<typename T> struct string_traits<std::optional<T>> final
320 {
321  static std::string_view
322  to_buf(std::span<char> buf, std::optional<T> const &value, ctx c = {})
323  {
324  if (pqxx::is_null(value))
325  return {};
326  else
327  // (No need to check: if the optional were empty, it'd be null.)
328  // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
329  return pqxx::to_buf(buf, *value, c);
330  }
331 
332  static std::optional<T> from_string(std::string_view text, ctx c = {})
333  {
334  return std::optional<T>{std::in_place, pqxx::from_string<T>(text, c)};
335  }
336 
337  static std::size_t size_buffer(std::optional<T> const &value) noexcept
338  {
339  if (pqxx::is_null(value))
340  return 0;
341  else
342  // (No need to check: if the optional were empty, it'd be null.)
343  // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
344  return pqxx::size_buffer(value.value());
345  }
346 };
347 
348 
349 template<typename T>
350 inline constexpr bool is_unquoted_safe<std::optional<T>>{is_unquoted_safe<T>};
351 
352 
353 template<typename... T> struct nullness<std::variant<T...>> final
354 {
355  static constexpr bool has_null = (pqxx::has_null<T>() or ...);
356  static constexpr bool always_null = (pqxx::always_null<T>() and ...);
357  [[nodiscard]] PQXX_PURE static constexpr bool
358  is_null(std::variant<T...> const &value) noexcept
359  {
360  return value.valueless_by_exception() or
361  std::visit(
362  [](auto const &i) noexcept {
363  return nullness<std::remove_cvref_t<decltype(i)>>::is_null(i);
364  },
365  value);
366  }
367 
368  // We don't support `null()` for `std::variant`.
372  static constexpr std::variant<T...> null() = delete;
373 };
374 
375 
376 template<typename... T> struct string_traits<std::variant<T...>> final
377 {
378  static std::string_view
379  to_buf(std::span<char> buf, std::variant<T...> const &value, ctx c = {})
380  {
381  return std::visit(
382  [buf, c](auto const &i) {
383  using field_t = std::remove_cvref_t<decltype(i)>;
384  return pqxx::to_buf<field_t>(buf, i, c);
385  },
386  value);
387  }
388  static std::size_t size_buffer(std::variant<T...> const &value) noexcept
389  {
390  if (pqxx::is_null(value))
391  return 0;
392  else
393  return std::visit(
394  [](auto const &i) noexcept { return pqxx::size_buffer(i); }, value);
395  }
396 
401  static std::variant<T...> from_string(std::string_view, ctx = {}) = delete;
402 };
403 
404 
405 template<typename... Args>
406 inline constexpr format param_format(std::variant<Args...> const &value)
407 {
408  return std::visit([](auto &v) { return param_format(v); }, value);
409 }
410 
411 
412 template<typename... T>
413 inline constexpr bool is_unquoted_safe<std::variant<T...>>{
414  (is_unquoted_safe<T> and ...)};
415 
416 
417 template<typename T>
418 inline T from_string(std::stringstream const &text, ctx c = {})
419 {
420  return from_string<T>(text.str(), c);
421 }
422 
423 
424 template<> struct string_traits<std::nullptr_t> final
425 {
426  [[deprecated("Do not convert nulls.")]] static constexpr zview
427  to_buf(std::span<char>, std::nullptr_t const &, ctx = {}) noexcept
428  {
429  return {};
430  }
431 
432  [[deprecated("Do not convert nulls.")]] static constexpr std::size_t
433  size_buffer(std::nullptr_t = nullptr) noexcept
434  {
435  return 0;
436  }
437  static std::nullptr_t from_string(std::string_view, ctx = {}) = delete;
438 };
439 
440 
441 template<> struct string_traits<std::nullopt_t> final
442 {
443  [[deprecated("Do not convert nulls.")]] static constexpr zview
444  to_buf(char *, char *, std::nullopt_t const &) noexcept
445  {
446  return {};
447  }
448 
449  [[deprecated("Do not convert nulls.")]] static constexpr std::size_t
450  size_buffer(std::nullopt_t) noexcept
451  {
452  return 0;
453  }
454  static std::nullopt_t from_string(std::string_view, ctx = {}) = delete;
455 };
456 
457 
458 template<> struct string_traits<std::monostate> final
459 {
460  [[deprecated("Do not convert nulls.")]] static constexpr zview
461  to_buf(char *, char *, std::monostate const &) noexcept
462  {
463  return {};
464  }
465 
466  [[deprecated("Do not convert nulls.")]] static constexpr std::size_t
467  size_buffer(std::monostate) noexcept
468  {
469  return 0;
470  }
471  [[deprecated("Do not convert nulls.")]] static std::monostate
472  from_string(std::string_view, ctx = {}) = delete;
473 };
474 
475 
476 template<> inline constexpr bool is_unquoted_safe<std::nullptr_t>{true};
477 
478 
479 template<> struct nullness<char const *> final
480 {
481  static constexpr bool has_null = true;
482  static constexpr bool always_null = false;
483  [[nodiscard]] PQXX_PURE PQXX_ZARGS static constexpr bool
484  is_null(char const *t) noexcept
485  {
486  return t == nullptr;
487  }
488  [[nodiscard]] PQXX_PURE static constexpr char const *null() noexcept
489  {
490  return nullptr;
491  }
492 };
493 
494 
496 
505 template<> struct string_traits<char const *> final
506 {
507  static char const *from_string(std::string_view text, ctx = {}) = delete;
508 
509  constexpr PQXX_ZARGS static std::string_view
510  to_buf(std::span<char>, char const *const &value, ctx = {}) noexcept
511  {
512  return value;
513  }
514 
515  PQXX_ZARGS static constexpr std::size_t
516  size_buffer(char const *value) noexcept
517  {
518  if (pqxx::is_null(value))
519  return 0;
520  else
521  // std::char_traits::length() is like std::strlen(), but constexpr.
522  return std::char_traits<char>::length(value);
523  }
524 };
525 
526 
527 template<> struct nullness<char *> final
528 {
529  static constexpr bool has_null = true;
530  static constexpr bool always_null = false;
531  [[nodiscard]] PQXX_PURE static constexpr bool is_null(char const *t) noexcept
532  {
533  return t == nullptr;
534  }
535  [[nodiscard]] PQXX_PURE static constexpr char *null() { return nullptr; }
536 };
537 
538 
540 
549 template<> struct string_traits<char *> final
550 {
551  static std::string_view
552  to_buf(std::span<char> buf, char *const &value, ctx c = {})
553  {
554  return pqxx::to_buf<char const *>(buf, value, c);
555  }
556  static std::size_t size_buffer(char *const &value) noexcept
557  {
558  if (pqxx::is_null(value))
559  return 0;
560  else
561  return pqxx::size_buffer(const_cast<char const *>(value));
562  }
563 
564  static char *from_string(std::string_view, ctx = {}) = delete;
565 };
566 
567 
568 template<std::size_t N> struct nullness<char[N]> final : no_null<char[N]>
569 {};
570 
571 
573 
576 template<std::size_t N> struct string_traits<char[N]> final
577 {
578  static constexpr zview
579  to_buf(std::span<char>, char const (&value)[N], ctx = {}) noexcept
580  {
581  return zview{value, N - 1};
582  }
583 
584  static constexpr std::size_t size_buffer(char const (&)[N]) noexcept
585  {
586  return N;
587  }
588 
590  static void from_string(std::string_view, ctx = {}) = delete;
591 };
592 
593 
594 template<> struct nullness<std::string> final : no_null<std::string>
595 {};
596 
597 
598 template<> struct string_traits<std::string> final
599 {
600  PQXX_INLINE_ONLY static std::string
601  from_string(std::string_view text, ctx = {})
602  {
603  return std::string{text};
604  }
605 
606  PQXX_INLINE_ONLY static std::string_view
607  to_buf(std::span<char>, std::string const &value, ctx = {})
608  {
609  return {std::data(value), std::size(value)};
610  }
611 
612  PQXX_INLINE_ONLY static constexpr std::size_t
613  size_buffer(std::string const &value) noexcept
614  {
615  return std::size(value);
616  }
617 };
618 
619 
621 
625 template<> struct nullness<std::string_view> final : no_null<std::string_view>
626 {};
627 
628 
630 
635 template<> struct string_traits<std::string_view> final
636 {
637  PQXX_INLINE_ONLY static constexpr std::size_t
638  size_buffer(std::string_view const &value) noexcept
639  {
640  return std::size(value);
641  }
642 
643  PQXX_INLINE_ONLY static std::string_view
644  to_buf(std::span<char>, std::string_view const &value, ctx = {})
645  {
646  return value;
647  }
648 
649  PQXX_INLINE_ONLY static std::string_view
650  from_string(std::string_view value, ctx = {})
651  {
652  return value;
653  }
654 };
655 
656 
657 template<> struct nullness<zview> final : no_null<zview>
658 {};
659 
660 
662 template<> struct string_traits<zview> final
663 {
664  PQXX_INLINE_ONLY static constexpr std::size_t
665  size_buffer(std::string_view const &value) noexcept
666  {
667  return std::size(value);
668  }
669 
670  static constexpr zview to_buf(std::span<char>, zview const &value, ctx = {})
671  {
672  return value;
673  }
674 
676 
680  static zview from_string(std::string_view, ctx = {}) = delete;
681 };
682 
683 
684 template<>
685 struct nullness<std::stringstream> final : no_null<std::stringstream>
686 {};
687 
688 
689 template<> struct string_traits<std::stringstream> final
690 {
691  static std::size_t size_buffer(std::stringstream const &) = delete;
692 
693  static std::stringstream from_string(std::string_view text, ctx = {})
694  {
695  std::stringstream stream;
696  stream.write(text.data(), std::streamsize(std::size(text)));
697  return stream;
698  }
699 
700  static std::string_view
701  to_buf(std::span<char>, std::stringstream const &, ctx = {}) = delete;
702 };
703 
704 
705 template<>
706 struct nullness<std::nullptr_t> final : all_null<std::nullptr_t, nullptr>
707 {};
708 
709 template<>
710 struct nullness<std::nullopt_t> final : all_null<std::nullopt_t, std::nullopt>
711 {};
712 
713 template<>
714 struct nullness<std::monostate> final
715  : all_null<std::monostate, std::monostate{}>
716 {};
717 
718 
719 template<typename T> struct nullness<std::unique_ptr<T>> final
720 {
721  static constexpr bool has_null = true;
722  static constexpr bool always_null = false;
723  [[nodiscard]] PQXX_PURE static constexpr bool
724  is_null(std::unique_ptr<T> const &t) noexcept
725  {
726  return not t or pqxx::is_null(*t);
727  }
728  [[nodiscard]] PQXX_PURE static constexpr std::unique_ptr<T> null() noexcept
729  {
730  return {};
731  }
732 };
733 
734 
735 template<typename T, typename... Args>
736 struct string_traits<std::unique_ptr<T, Args...>> final
737 {
738  static std::unique_ptr<T> from_string(std::string_view text, ctx c = {})
739  {
740  return std::make_unique<T>(pqxx::from_string<T>(text, c));
741  }
742 
743  static std::string_view to_buf(
744  std::span<char> buf, std::unique_ptr<T, Args...> const &value, ctx c = {})
745  {
746  if (not value)
747  internal::throw_null_conversion(name_type<std::unique_ptr<T>>(), c.loc);
748  return pqxx::to_buf(buf, *value, c);
749  }
750 
751  static std::size_t
752  size_buffer(std::unique_ptr<T, Args...> const &value) noexcept
753  {
754  if (pqxx::is_null(value))
755  return 0;
756  else
757  return pqxx::size_buffer(*value.get());
758  }
759 };
760 
761 
762 template<typename T, typename... Args>
763 inline format param_format(std::unique_ptr<T, Args...> const &value)
764 {
765  return param_format(*value);
766 }
767 
768 
769 template<typename T, typename... Args>
770 inline constexpr bool is_unquoted_safe<std::unique_ptr<T, Args...>>{
772 
773 
774 template<typename T> struct nullness<std::shared_ptr<T>> final
775 {
776  static constexpr bool has_null = true;
777  static constexpr bool always_null = false;
778  [[nodiscard]] PQXX_PURE static constexpr bool
779  is_null(std::shared_ptr<T> const &t) noexcept
780  {
781  return not t or pqxx::is_null(*t);
782  }
783  [[nodiscard]] PQXX_PURE static constexpr std::shared_ptr<T> null() noexcept
784  {
785  return {};
786  }
787 };
788 
789 
790 template<typename T> struct string_traits<std::shared_ptr<T>> final
791 {
792  static std::shared_ptr<T> from_string(std::string_view text, ctx c = {})
793  {
794  return std::make_shared<T>(pqxx::from_string<T>(text, c));
795  }
796 
797  static std::string_view
798  to_buf(std::span<char> buf, std::shared_ptr<T> const &value, ctx c = {})
799  {
800  if (not value)
801  internal::throw_null_conversion(name_type<std::shared_ptr<T>>(), c.loc);
802  return pqxx::to_buf(buf, *value, c);
803  }
804  static std::size_t size_buffer(std::shared_ptr<T> const &value) noexcept
805  {
806  if (pqxx::is_null(value))
807  return 0;
808  else
809  return pqxx::size_buffer(*value);
810  }
811 };
812 
813 
814 template<typename T> format param_format(std::shared_ptr<T> const &value)
815 {
816  return param_format(*value);
817 }
818 
819 
820 template<typename T>
821 inline constexpr bool is_unquoted_safe<std::shared_ptr<T>>{
823 
824 
825 template<binary DATA> struct nullness<DATA> final : no_null<DATA>
826 {};
827 
828 
829 template<binary DATA> struct string_traits<DATA> final
830 {
831  static std::size_t size_buffer(DATA const &value) noexcept
832  {
833  return internal::size_esc_bin(std::size(value));
834  }
835 
836  static std::string_view
837  to_buf(std::span<char> buf, DATA const &value, ctx c = {})
838  {
839  // Budget for this type is precise.
840  auto const budget{size_buffer(value)};
841  if (std::cmp_less(std::size(buf), budget))
842  throw conversion_overrun{
843  "Not enough buffer space to escape binary data.", c.loc};
844  internal::esc_bin(value, buf);
845  // The budget included a terminating zero, which we do not include in the
846  // view.
847  return {std::data(buf), budget - 1};
848  }
849 
851  static DATA from_string(std::string_view text, ctx c = {})
852  {
853  auto const size{pqxx::internal::size_unesc_bin(std::size(text))};
854  DATA buf{};
855  if constexpr (requires { buf.resize(std::size_t{}); })
856  {
857  // Make `buf` allocate the number of bytes we need to store.
858  buf.resize(size);
859  }
860  else
861  {
862  // There's no suitable `DATA::resize()`. But perhaps the caller has
863  // ensured that `DATA` is a type that inherently has the right size.
864  // Might a `std::array<std::byte, ...>` for instance.
865  if (std::size(buf) != size)
866  throw conversion_error{
867  std::format(
868  "Can't convert binary data from SQL text to {}: I don't know how "
869  "to "
870  "resize that type.",
871  name_type<DATA>()),
872  c.loc};
873  }
874 
875  pqxx::internal::unesc_bin(text, buf, c.loc);
876  return buf;
877  }
878 };
879 } // namespace pqxx
880 
881 
882 namespace pqxx::internal
883 {
884 template<nonbinary_range TYPE>
885 inline std::size_t array_into_buf(
886  std::span<char> buf, TYPE const &value, std::size_t budget, ctx c = {});
887 
888 
890 
893 template<typename T> struct nonbinary_range_traits
894 {
895  using elt_type = std::remove_cvref_t<value_type<T>>;
897  static constexpr zview s_null{"NULL"};
898 
899  static std::size_t size_buffer(T const &value) noexcept
900  {
901  if constexpr (is_unquoted_safe<elt_type>)
902  return 3 + std::accumulate(
903  std::begin(value), std::end(value), std::size_t{},
904  [](std::size_t acc, elt_type const &elt) {
905  // Budget for each element includes a terminating zero.
906  // We won't actually be wanting those, but don't subtract
907  // that one byte: we want room for a separator instead.
908  // However, std::size(s_null) doesn't account for the
909  // terminating zero, so add one to make s_null pay for its
910  // own separator.
911  return acc + (pqxx::is_null(elt) ?
912  (std::size(s_null) + 1) :
914  });
915  else
916  return 3 + std::accumulate(
917  std::begin(value), std::end(value), std::size_t{},
918  [](std::size_t acc, elt_type const &elt) {
919  // Opening and closing quotes, plus worst-case escaping,
920  // plus one byte for the separator.
921  std::size_t const elt_size{
922  pqxx::is_null(elt) ? std::size(s_null) :
924  return acc + 2 * elt_size + 3;
925  });
926  }
927 
928  static std::string_view
929  to_buf(std::span<char> buf, T const &value, ctx c = {})
930  {
931  auto const sz{
932  pqxx::internal::array_into_buf(buf, value, size_buffer(value), c)};
933  return {std::data(buf), sz};
934  }
935 };
936 } // namespace pqxx::internal
937 
938 
939 namespace pqxx
940 {
941 template<nonbinary_range T> struct nullness<T> final : no_null<T>
942 {};
943 
944 
946 
951 template<nonbinary_range T>
953 {};
954 
955 
957 template<nonbinary_range T> inline constexpr format param_format(T const &)
958 {
959  return format::text;
960 }
961 
962 
964 template<binary T> inline constexpr format param_format(T const &)
965 {
966  return format::binary;
967 }
968 
969 
970 template<nonbinary_range T> inline constexpr bool is_sql_array<T>{true};
971 
972 
973 template<typename TYPE>
974 PQXX_INLINE_COV inline std::string to_string(TYPE const &value, ctx c)
975 {
976  if (is_null(value))
977  throw conversion_error{
978  std::format("Attempt to convert null to a string.", name_type<TYPE>()),
979  c.loc};
980 
981  if constexpr (pqxx::always_null<TYPE>())
982  {
983  // Have to separate out this case: some functions in the "regular" code
984  // may not exist in the "always null" case.
986  // C++23: The return may not be needed when std::unreachable is available.
987  return {};
988  }
989  else
990  {
991  std::string buf;
992  // We can't just reserve() space; modifying the terminating zero leads to
993  // undefined behaviour.
994  buf.resize(pqxx::size_buffer(value));
995  std::size_t const stop{pqxx::into_buf(buf, value, c)};
996  buf.resize(stop);
997  return buf;
998  }
999 }
1000 
1001 
1002 template<> inline std::string to_string(float const &value, ctx c)
1003 {
1004  return pqxx::internal::to_string_float(value, c);
1005 }
1006 template<> inline std::string to_string(double const &value, ctx c)
1007 {
1008  return pqxx::internal::to_string_float(value, c);
1009 }
1010 template<> inline std::string to_string(long double const &value, ctx c)
1011 {
1012  return pqxx::internal::to_string_float(value, c);
1013 }
1014 
1015 // clang-tidy rule bug:
1016 // NOLINTNEXTLINE(misc-unused-parameters)
1017 template<> inline std::string to_string(std::stringstream const &value, ctx)
1018 {
1019  return value.str();
1020 }
1021 
1022 
1023 template<typename T>
1024 inline void into_string(T const &value, std::string &out, ctx c = {})
1025 {
1026  if (is_null(value))
1027  throw conversion_error{
1028  std::format("Attempt to convert null {} to a string.", name_type<T>()),
1029  c.loc};
1030 
1031  // We can't just reserve() data; modifying the terminating zero leads to
1032  // undefined behaviour.
1033  out.resize(size_buffer(value));
1034  auto const data{out.data()};
1035  auto const end{into_buf({data, std::size(out)}, value, c)};
1036  out.resize(static_cast<std::size_t>(end - data));
1037 }
1038 } // namespace pqxx
1039 #endif
Marker-type wrapper: zero-terminated std::string_view.
Definition: zview.hxx:55
#define PQXX_SPECIALIZE_INT_TRAIT(typ)
Definition: conversions.hxx:248
Value conversion failed, e.g. when converting "Hello" to int.
Definition: except.hxx:612
#define PQXX_ZARGS
Definition: header-pre.hxx:136
#define PQXX_COLD
Definition: header-pre.hxx:72
#define PQXX_LIBEXPORT
Definition: header-pre.hxx:206
#define PQXX_PURE
Definition: header-pre.hxx:64
#define PQXX_ASSUME(condition)
Definition: header-pre.hxx:228
#define PQXX_INLINE_COV
Don't generate out-of-line version of inline function for coverage runs.
Definition: header-pre.hxx:98
#define PQXX_INLINE_ONLY
Definition: header-pre.hxx:83
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
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
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
constexpr PQXX_PURE int digit_to_number(char c) noexcept
Compute numeric value of given textual digit (assuming that it is a digit).
Definition: conversions.hxx:37
constexpr PQXX_PURE 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:417
std::string state_buffer_overrun(int have_bytes, int need_bytes)
Summarize buffer overrun.
Definition: strconv.cxx:156
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:970
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:313
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:244
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:292
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:1024
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 PQXX_LIBEXPORT T from_string(std::string_view text, ctx={})
Definition: strconv.cxx:345
static constexpr std::size_t digits10(std::size_t value) noexcept
Definition: conversions.hxx:156
static constexpr PQXX_INLINE_COV std::size_t size_buffer(T const &) noexcept
Definition: conversions.hxx:164
static PQXX_LIBEXPORT 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:215
static constexpr PQXX_INLINE_ONLY std::size_t size_buffer(T const &) noexcept
Definition: conversions.hxx:220
static PQXX_LIBEXPORT T from_string(std::string_view text, ctx={})
Definition: strconv.cxx:390
static PQXX_LIBEXPORT 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:894
std::remove_cvref_t< value_type< T > > elt_type
Definition: conversions.hxx:895
static std::string_view to_buf(std::span< char > buf, T const &value, ctx c={})
Definition: conversions.hxx:929
static std::size_t size_buffer(T const &value) noexcept
Definition: conversions.hxx:899
static constexpr zview s_null
Definition: conversions.hxx:897
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:531
PQXX_PURE static constexpr PQXX_ZARGS bool is_null(char const *t) noexcept
Definition: conversions.hxx:484
static constexpr PQXX_PURE bool is_null(std::optional< T > const &v) noexcept
Definition: conversions.hxx:301
static constexpr PQXX_PURE bool is_null(std::shared_ptr< T > const &t) noexcept
Definition: conversions.hxx:779
static constexpr PQXX_PURE bool is_null(std::unique_ptr< T > const &t) noexcept
Definition: conversions.hxx:724
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:837
static DATA from_string(std::string_view text, ctx c={})
Convert a string to binary data.
Definition: conversions.hxx:851
static std::size_t size_buffer(DATA const &value) noexcept
Definition: conversions.hxx:831
static constexpr std::size_t size_buffer(bool const &) noexcept
Definition: conversions.hxx:288
static constexpr zview to_buf(std::span< char >, bool const &value, ctx={}) noexcept
Definition: conversions.hxx:283
static std::size_t size_buffer(char *const &value) noexcept
Definition: conversions.hxx:556
static std::string_view to_buf(std::span< char > buf, char *const &value, ctx c={})
Definition: conversions.hxx:552
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:510
static constexpr PQXX_ZARGS std::size_t size_buffer(char const *value) noexcept
Definition: conversions.hxx:516
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:579
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:584
static constexpr zview to_buf(char *, char *, std::monostate const &) noexcept
Definition: conversions.hxx:461
static constexpr std::size_t size_buffer(std::monostate) noexcept
Definition: conversions.hxx:467
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:444
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:450
static constexpr std::size_t size_buffer(std::nullptr_t=nullptr) noexcept
Definition: conversions.hxx:433
static constexpr zview to_buf(std::span< char >, std::nullptr_t const &, ctx={}) noexcept
Definition: conversions.hxx:427
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:332
static std::size_t size_buffer(std::optional< T > const &value) noexcept
Definition: conversions.hxx:337
static std::string_view to_buf(std::span< char > buf, std::optional< T > const &value, ctx c={})
Definition: conversions.hxx:322
static std::shared_ptr< T > from_string(std::string_view text, ctx c={})
Definition: conversions.hxx:792
static std::size_t size_buffer(std::shared_ptr< T > const &value) noexcept
Definition: conversions.hxx:804
static std::string_view to_buf(std::span< char > buf, std::shared_ptr< T > const &value, ctx c={})
Definition: conversions.hxx:798
static PQXX_INLINE_ONLY std::string from_string(std::string_view text, ctx={})
Definition: conversions.hxx:601
static PQXX_INLINE_ONLY std::string_view to_buf(std::span< char >, std::string const &value, ctx={})
Definition: conversions.hxx:607
static constexpr PQXX_INLINE_ONLY std::size_t size_buffer(std::string const &value) noexcept
Definition: conversions.hxx:613
static PQXX_INLINE_ONLY std::string_view from_string(std::string_view value, ctx={})
Definition: conversions.hxx:650
static PQXX_INLINE_ONLY std::string_view to_buf(std::span< char >, std::string_view const &value, ctx={})
Definition: conversions.hxx:644
static constexpr PQXX_INLINE_ONLY std::size_t size_buffer(std::string_view const &value) noexcept
Definition: conversions.hxx:638
static std::stringstream from_string(std::string_view text, ctx={})
Definition: conversions.hxx:693
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:743
static std::size_t size_buffer(std::unique_ptr< T, Args... > const &value) noexcept
Definition: conversions.hxx:752
static std::unique_ptr< T > from_string(std::string_view text, ctx c={})
Definition: conversions.hxx:738
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:379
static std::size_t size_buffer(std::variant< T... > const &value) noexcept
Definition: conversions.hxx:388
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:670
static constexpr PQXX_INLINE_ONLY std::size_t size_buffer(std::string_view const &value) noexcept
Definition: conversions.hxx:665
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