libpqxx
The C++ client library for PostgreSQL
strconv.hxx
Go to the documentation of this file.
1 /* String conversion definitions.
2  *
3  * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/stringconv instead.
4  *
5  * Copyright (c) 2000-2025, Jeroen T. Vermeulen.
6  *
7  * See COPYING for copyright license. If you did not receive a file called
8  * COPYING with this source code, please notify the distributor of this
9  * mistake, or contact the author.
10  */
11 #ifndef PQXX_H_STRCONV
12 #define PQXX_H_STRCONV
13 
14 #if !defined(PQXX_HEADER_PRE)
15 # error "Include libpqxx headers as <pqxx/header>, not <pqxx/header.hxx>."
16 #endif
17 
18 #include <algorithm>
19 #include <charconv>
20 #include <cstring>
21 #include <limits>
22 #include <sstream>
23 #include <stdexcept>
24 #include <typeinfo>
25 
26 // C++20: Assume support.
27 #if defined(PQXX_HAVE_RANGES)
28 # include <ranges>
29 #endif
30 
31 #include "pqxx/except.hxx"
32 #include "pqxx/util.hxx"
33 #include "pqxx/zview.hxx"
34 
35 
36 namespace pqxx
37 {
62 
69 template<typename TYPE, typename ENABLE = void> struct nullness
70 {
72  static bool has_null;
73 
75  static bool always_null;
76 
78  static bool is_null(TYPE const &value);
79 
81 
86  [[nodiscard]] static TYPE null();
87 };
88 
89 
91 template<typename TYPE> struct no_null
92 {
94 
104  static constexpr bool has_null = false;
105 
107 
110  static constexpr bool always_null = false;
111 
113 
117  [[nodiscard]] static constexpr bool is_null(TYPE const &) noexcept
118  {
119  return false;
120  }
121 };
122 
123 
125 
132 template<typename TYPE> struct string_traits
133 {
135 
138  static constexpr bool converts_to_string{false};
139 
141 
144  static constexpr bool converts_from_string{false};
145 
147 
166  [[nodiscard]] static inline zview
167  to_buf(char *begin, char *end, TYPE const &value);
168 
170  /* @warning A null value has no string representation. Do not pass a null.
171  *
172  * Writes value's string representation into the buffer, starting exactly at
173  * @c begin, and ensuring a trailing zero. Returns the address just beyond
174  * the trailing zero, so the caller could use it as the @c begin for another
175  * call to @c into_buf writing a next value.
176  */
177  static inline char *into_buf(char *begin, char *end, TYPE const &value);
178 
180 
185  [[nodiscard]] static inline TYPE from_string(std::string_view text);
186 
187  // C++20: Can we make these all constexpr?
189 
193  [[nodiscard]] static inline std::size_t
194  size_buffer(TYPE const &value) noexcept;
195 
196  // TODO: Move is_unquoted_safe into the traits after all?
197 };
198 
199 
201 
217 template<typename TYPE> [[noreturn]] void oops_forbidden_conversion() noexcept;
218 
219 
221 
226 template<typename TYPE> struct forbidden_conversion
227 {
228  static constexpr bool converts_to_string{false};
229  static constexpr bool converts_from_string{false};
230  [[noreturn]] static zview to_buf(char *, char *, TYPE const &)
231  {
232  oops_forbidden_conversion<TYPE>();
233  }
234  [[noreturn]] static char *into_buf(char *, char *, TYPE const &)
235  {
236  oops_forbidden_conversion<TYPE>();
237  }
238  [[noreturn]] static TYPE from_string(std::string_view)
239  {
240  oops_forbidden_conversion<TYPE>();
241  }
242  [[noreturn]] static std::size_t size_buffer(TYPE const &) noexcept
243  {
244  oops_forbidden_conversion<TYPE>();
245  }
246 };
247 
248 
250 
265 template<> struct string_traits<char> : forbidden_conversion<char>
266 {};
267 
268 
270 
283 template<>
284 struct string_traits<unsigned char> : forbidden_conversion<unsigned char>
285 {};
286 
287 
289 
302 template<>
303 struct string_traits<signed char> : forbidden_conversion<signed char>
304 {};
305 
306 
308 
313 template<> struct string_traits<std::byte> : forbidden_conversion<std::byte>
314 {};
315 
316 
318 template<typename ENUM>
319 struct nullness<ENUM, std::enable_if_t<std::is_enum_v<ENUM>>> : no_null<ENUM>
320 {};
321 
322 
323 // C++20: Concepts for "converts from string" & "converts to string."
324 } // namespace pqxx
325 
326 
327 namespace pqxx::internal
328 {
330 
339 template<typename ENUM> struct enum_traits
340 {
341  using impl_type = std::underlying_type_t<ENUM>;
343 
344  static constexpr bool converts_to_string{true};
345  static constexpr bool converts_from_string{true};
346 
347  [[nodiscard]] static constexpr zview
348  to_buf(char *begin, char *end, ENUM const &value)
349  {
350  return impl_traits::to_buf(begin, end, to_underlying(value));
351  }
352 
353  static constexpr char *into_buf(char *begin, char *end, ENUM const &value)
354  {
355  return impl_traits::into_buf(begin, end, to_underlying(value));
356  }
357 
358  [[nodiscard]] static ENUM from_string(std::string_view text)
359  {
360  return static_cast<ENUM>(impl_traits::from_string(text));
361  }
362 
363  [[nodiscard]] static std::size_t size_buffer(ENUM const &value) noexcept
364  {
365  return impl_traits::size_buffer(to_underlying(value));
366  }
367 
368 private:
369  // C++23: Replace with std::to_underlying.
370  static constexpr impl_type to_underlying(ENUM const &value) noexcept
371  {
372  return static_cast<impl_type>(value);
373  }
374 };
375 } // namespace pqxx::internal
376 
377 
378 // We used to inline type_name<ENUM>, but this triggered a "double free" error
379 // on program exit, when libpqxx was built as a shared library on Debian with
380 // gcc 12.
381 
383 
394 #define PQXX_DECLARE_ENUM_CONVERSION(ENUM) \
395  template<> struct string_traits<ENUM> : pqxx::internal::enum_traits<ENUM> \
396  {}; \
397  template<> \
398  inline constexpr PQXX_PURE std::string_view name_type<ENUM>() noexcept \
399  { \
400  return #ENUM; \
401  } \
402  template<> [[maybe_unused]] inline std::string_view const type_name<ENUM> \
403  { \
404  #ENUM \
405  }
406 
407 
408 namespace pqxx
409 {
411 
423 template<typename TYPE>
424 [[nodiscard]] inline TYPE from_string(std::string_view text)
425 {
427 }
428 
429 
431 
437 template<>
438 [[nodiscard]] inline std::string_view from_string(std::string_view text)
439 {
440  return text;
441 }
442 
443 
445 
452 template<typename T> inline void from_string(std::string_view text, T &value)
453 {
454  value = from_string<T>(text);
455 }
456 
457 
459 
464 template<typename TYPE> inline std::string to_string(TYPE const &value);
465 
466 
468 
475 template<typename... TYPE>
476 [[nodiscard]] inline std::vector<std::string_view>
477 to_buf(char *here, char const *end, TYPE... value)
478 {
479  PQXX_ASSUME(here <= end);
480  return {[&here, end](auto v) {
481  auto begin = here;
482  here = string_traits<decltype(v)>::into_buf(begin, end, v);
483  // Exclude the trailing zero out of the string_view.
484  auto len{static_cast<std::size_t>(here - begin) - 1};
485  return std::string_view{begin, len};
486  }(value)...};
487 }
488 
490 
493 template<typename TYPE>
494 inline void into_string(TYPE const &value, std::string &out);
495 
496 
498 template<typename TYPE>
499 [[nodiscard]] inline constexpr bool is_null(TYPE const &value) noexcept
500 {
501  return nullness<strip_t<TYPE>>::is_null(value);
502 }
503 
504 
506 
509 template<typename... TYPE>
510 [[nodiscard]] inline std::size_t size_buffer(TYPE const &...value) noexcept
511 {
512  return (string_traits<strip_t<TYPE>>::size_buffer(value) + ...);
513 }
514 
515 
517 
523 template<typename TYPE> inline constexpr bool is_sql_array{false};
524 
525 
527 
539 template<typename TYPE> inline constexpr bool is_unquoted_safe{false};
540 
541 
543 template<typename T> inline constexpr char array_separator{','};
544 
545 
547 
554 template<typename TYPE> inline constexpr format param_format(TYPE const &)
555 {
556  return format::text;
557 }
558 
559 
561 
570 template<typename TYPE>
571 inline zview generic_to_buf(char *begin, char *end, TYPE const &value)
572 {
573  using traits = string_traits<TYPE>;
574  // The trailing zero does not count towards the zview's size, so subtract 1
575  // from the result we get from into_buf().
576  if (is_null(value))
577  return {};
578  else
579  return {begin, traits::into_buf(begin, end, value) - begin - 1};
580 }
581 
582 
583 #if defined(PQXX_HAVE_CONCEPTS) && defined(PQXX_HAVE_RANGES)
584 
591 template<class TYPE>
592 concept binary = std::ranges::contiguous_range<TYPE> and
593  std::is_same_v<strip_t<value_type<TYPE>>, std::byte>;
594 #endif
595 
596 } // namespace pqxx
597 
598 
600 #endif
std::underlying_type_t< ExecStatusType > impl_type
Definition: strconv.hxx:341
Marker-type wrapper: zero-terminated std::string_view.
Definition: zview.hxx:37
#define PQXX_ASSUME(condition)
Definition: header-pre.hxx:187
static constexpr bool always_null
Are all values of this type null?
Definition: strconv.hxx:110
static char * into_buf(char *, char *, TYPE const &)
Definition: strconv.hxx:234
static TYPE from_string(std::string_view)
Definition: strconv.hxx:238
static constexpr bool is_null(TYPE const &) noexcept
Does a given value correspond to an SQL null value?
Definition: strconv.hxx:117
static zview to_buf(char *begin, char *end, TYPE const &value)
Return a string_view representing value, plus terminating zero.
Internal items for libpqxx' own use. Do not use these yourself.
Definition: encodings.cxx:32
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:510
Helper class for defining enum conversions.
Definition: strconv.hxx:339
static constexpr bool converts_to_string
Definition: strconv.hxx:344
T from_string(field const &value)
Convert a field's value to type T.
Definition: field.hxx:548
static zview to_buf(char *, char *, TYPE const &)
Definition: strconv.hxx:230
std::vector< std::string_view > to_buf(char *here, char const *end, TYPE...value)
Convert multiple values to strings inside a single buffer.
Definition: strconv.hxx:477
static TYPE from_string(std::string_view text)
Parse a string representation of a TYPE value.
constexpr format param_format(std::optional< T > const &value)
Definition: conversions.hxx:286
static bool has_null
Does this type have a null value?
Definition: strconv.hxx:72
PQXX_LIBEXPORT std::string to_string(field const &value)
Convert a field to a string.
format
Format code: is data text or binary?
Definition: types.hxx:81
constexpr bool is_null(TYPE const &value) noexcept
Is value null?
Definition: strconv.hxx:499
constexpr bool is_unquoted_safe
Can we use this type in arrays and composite types without quoting them?
Definition: strconv.hxx:539
static ENUM from_string(std::string_view text)
Definition: strconv.hxx:358
static std::size_t size_buffer(ENUM const &value) noexcept
Definition: strconv.hxx:363
static constexpr bool converts_from_string
Is conversion from string_view to TYPE supported?
Definition: strconv.hxx:144
void into_string(T const &value, std::string &out)
Definition: conversions.hxx:1286
static TYPE null()
Return a null value.
The home of all libpqxx classes, functions, templates, etc.
Definition: array.cxx:26
zview generic_to_buf(char *begin, char *end, TYPE const &value)
Implement string_traits::to_buf by calling into_buf.
Definition: strconv.hxx:571
void oops_forbidden_conversion() noexcept
Nonexistent function to indicate a disallowed type conversion.
Nullness traits describing a type which does not have a null value.
Definition: strconv.hxx:91
static constexpr bool converts_from_string
Definition: strconv.hxx:345
static constexpr zview to_buf(char *begin, char *end, ENUM const &value)
Definition: strconv.hxx:348
static constexpr bool has_null
Does TYPE have a "built-in null value"?
Definition: strconv.hxx:104
Traits class for use in string conversions.
Definition: strconv.hxx:132
static constexpr char * into_buf(char *begin, char *end, ENUM const &value)
Definition: strconv.hxx:353
static constexpr bool converts_to_string
Is conversion from TYPE to strings supported?
Definition: strconv.hxx:138
static bool always_null
Is this type always null?
Definition: strconv.hxx:75
Traits describing a type's "null value," if any.
Definition: strconv.hxx:69
static std::size_t size_buffer(TYPE const &) noexcept
Definition: strconv.hxx:242
static char * into_buf(char *begin, char *end, TYPE const &value)
Write value's string representation into buffer at begin.
static bool is_null(TYPE const &value)
Is value a null?
constexpr char array_separator
Element separator between SQL array elements of this type.
Definition: strconv.hxx:543
String traits for a forbidden type conversion.
Definition: strconv.hxx:226
std::remove_cv_t< std::remove_reference_t< TYPE >> strip_t
Remove any constness, volatile, and reference-ness from a type.
Definition: types.hxx:92
constexpr bool is_sql_array
Does this type translate to an SQL array?
Definition: strconv.hxx:523
static std::size_t size_buffer(TYPE const &value) noexcept
Estimate how much buffer space is needed to represent value.