libpqxx
The C++ client library for PostgreSQL
Loading...
Searching...
No Matches
strconv.hxx
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 __has_include(<ranges>)
28# include <ranges>
29#endif
30
31#include "pqxx/except.hxx"
32#include "pqxx/util.hxx"
33#include "pqxx/zview.hxx"
34
35
36namespace pqxx::internal
37{
39PQXX_LIBEXPORT std::string demangle_type_name(char const[]);
40} // namespace pqxx::internal
41
42
43namespace pqxx
44{
69
71
79template<typename TYPE>
80std::string const type_name{internal::demangle_type_name(typeid(TYPE).name())};
81
82
84
90template<typename TYPE, typename ENABLE = void> struct nullness
91{
93 static bool has_null;
94
96 static bool always_null;
97
99 static bool is_null(TYPE const &value);
100
102
107 [[nodiscard]] static TYPE null();
108};
109
110
112template<typename TYPE> struct no_null
113{
115
125 static constexpr bool has_null = false;
126
128
131 static constexpr bool always_null = false;
132
134
138 [[nodiscard]] static constexpr bool is_null(TYPE const &) noexcept
139 {
140 return false;
141 }
142};
143
144
146
153template<typename TYPE> struct string_traits
154{
156
159 static constexpr bool converts_to_string{false};
160
162
165 static constexpr bool converts_from_string{false};
166
168
187 [[nodiscard]] static inline zview
188 to_buf(char *begin, char *end, TYPE const &value);
189
191 /* @warning A null value has no string representation. Do not pass a null.
192 *
193 * Writes value's string representation into the buffer, starting exactly at
194 * @c begin, and ensuring a trailing zero. Returns the address just beyond
195 * the trailing zero, so the caller could use it as the @c begin for another
196 * call to @c into_buf writing a next value.
197 */
198 static inline char *into_buf(char *begin, char *end, TYPE const &value);
199
201
206 [[nodiscard]] static inline TYPE from_string(std::string_view text);
207
208 // C++20: Can we make these all constexpr?
210
214 [[nodiscard]] static inline std::size_t
215 size_buffer(TYPE const &value) noexcept;
216
217 // TODO: Move is_unquoted_safe into the traits after all?
218};
219
220
222
238template<typename TYPE> [[noreturn]] void oops_forbidden_conversion() noexcept;
239
240
242
247template<typename TYPE> struct forbidden_conversion
248{
249 static constexpr bool converts_to_string{false};
250 static constexpr bool converts_from_string{false};
251 [[noreturn]] static zview to_buf(char *, char *, TYPE const &)
252 {
253 oops_forbidden_conversion<TYPE>();
254 }
255 [[noreturn]] static char *into_buf(char *, char *, TYPE const &)
256 {
257 oops_forbidden_conversion<TYPE>();
258 }
259 [[noreturn]] static TYPE from_string(std::string_view)
260 {
261 oops_forbidden_conversion<TYPE>();
262 }
263 [[noreturn]] static std::size_t size_buffer(TYPE const &) noexcept
264 {
265 oops_forbidden_conversion<TYPE>();
266 }
267};
268
269
271
286template<> struct string_traits<char> : forbidden_conversion<char>
287{};
288
289
291
304template<>
305struct string_traits<unsigned char> : forbidden_conversion<unsigned char>
306{};
307
308
310
323template<>
324struct string_traits<signed char> : forbidden_conversion<signed char>
325{};
326
327
329
334template<> struct string_traits<std::byte> : forbidden_conversion<std::byte>
335{};
336
337
339template<typename ENUM>
340struct nullness<ENUM, std::enable_if_t<std::is_enum_v<ENUM>>> : no_null<ENUM>
341{};
342
343
344// C++20: Concepts for "converts from string" & "converts to string."
345} // namespace pqxx
346
347
348namespace pqxx::internal
349{
351
360template<typename ENUM> struct enum_traits
361{
362 using impl_type = std::underlying_type_t<ENUM>;
364
365 static constexpr bool converts_to_string{true};
366 static constexpr bool converts_from_string{true};
367
368 [[nodiscard]] static constexpr zview
369 to_buf(char *begin, char *end, ENUM const &value)
370 {
371 return impl_traits::to_buf(begin, end, to_underlying(value));
372 }
373
374 static constexpr char *into_buf(char *begin, char *end, ENUM const &value)
375 {
376 return impl_traits::into_buf(begin, end, to_underlying(value));
377 }
378
379 [[nodiscard]] static ENUM from_string(std::string_view text)
380 {
381 return static_cast<ENUM>(impl_traits::from_string(text));
382 }
383
384 [[nodiscard]] static std::size_t size_buffer(ENUM const &value) noexcept
385 {
386 return impl_traits::size_buffer(to_underlying(value));
387 }
388
389private:
390 // C++23: Replace with std::to_underlying.
391 static constexpr impl_type to_underlying(ENUM const &value) noexcept
392 {
393 return static_cast<impl_type>(value);
394 }
395};
396} // namespace pqxx::internal
397
398
399// We used to inline type_name<ENUM>, but this triggered a "double free" error
400// on program exit, when libpqxx was built as a shared library on Debian with
401// gcc 12.
402
404
415#define PQXX_DECLARE_ENUM_CONVERSION(ENUM) \
416 template<> struct string_traits<ENUM> : pqxx::internal::enum_traits<ENUM> \
417 {}; \
418 template<> inline std::string_view const type_name<ENUM> \
419 { \
420 #ENUM \
421 }
422
423
424namespace pqxx
425{
427
439template<typename TYPE>
440[[nodiscard]] inline TYPE from_string(std::string_view text)
441{
443}
444
445
447
453template<>
454[[nodiscard]] inline std::string_view from_string(std::string_view text)
455{
456 return text;
457}
458
459
461
468template<typename T> inline void from_string(std::string_view text, T &value)
469{
470 value = from_string<T>(text);
471}
472
473
475
480template<typename TYPE> inline std::string to_string(TYPE const &value);
481
482
484
491template<typename... TYPE>
492[[nodiscard]] inline std::vector<std::string_view>
493to_buf(char *here, char const *end, TYPE... value)
494{
495 PQXX_ASSUME(here <= end);
496 return {[&here, end](auto v) {
497 auto begin = here;
498 here = string_traits<decltype(v)>::into_buf(begin, end, v);
499 // Exclude the trailing zero out of the string_view.
500 auto len{static_cast<std::size_t>(here - begin) - 1};
501 return std::string_view{begin, len};
502 }(value)...};
503}
504
506
509template<typename TYPE>
510inline void into_string(TYPE const &value, std::string &out);
511
512
514template<typename TYPE>
515[[nodiscard]] inline constexpr bool is_null(TYPE const &value) noexcept
516{
517 return nullness<strip_t<TYPE>>::is_null(value);
518}
519
520
522
525template<typename... TYPE>
526[[nodiscard]] inline std::size_t size_buffer(TYPE const &...value) noexcept
527{
528 return (string_traits<strip_t<TYPE>>::size_buffer(value) + ...);
529}
530
531
533
539template<typename TYPE> inline constexpr bool is_sql_array{false};
540
541
543
555template<typename TYPE> inline constexpr bool is_unquoted_safe{false};
556
557
559template<typename T> inline constexpr char array_separator{','};
560
561
563
570template<typename TYPE> inline constexpr format param_format(TYPE const &)
571{
572 return format::text;
573}
574
575
577
586template<typename TYPE>
587inline zview generic_to_buf(char *begin, char *end, TYPE const &value)
588{
589 using traits = string_traits<TYPE>;
590 // The trailing zero does not count towards the zview's size, so subtract 1
591 // from the result we get from into_buf().
592 if (is_null(value))
593 return {};
594 else
595 return {begin, traits::into_buf(begin, end, value) - begin - 1};
596}
597
598
599#if defined(PQXX_HAVE_CONCEPTS)
601
607template<class TYPE>
608concept binary = std::ranges::contiguous_range<TYPE> and
609 std::is_same_v<strip_t<value_type<TYPE>>, std::byte>;
610#endif
612} // namespace pqxx
613
614
615#include "pqxx/internal/conversions.hxx"
616#endif
Marker-type wrapper: zero-terminated std::string_view.
Definition zview.hxx:38
Internal items for libpqxx' own use. Do not use these yourself.
Definition encodings.cxx:33
std::string demangle_type_name(char const raw[])
Attempt to demangle std::type_info::name() to something human-readable.
Definition strconv.cxx:227
The home of all libpqxx classes, functions, templates, etc.
Definition array.cxx:27
std::string const type_name
A human-readable name for a type, used in error messages and such.
Definition strconv.hxx:80
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:493
constexpr char array_separator
Element separator between SQL array elements of this type.
Definition strconv.hxx:559
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:526
void oops_forbidden_conversion() noexcept
Nonexistent function to indicate a disallowed type conversion.
std::remove_cv_t< std::remove_reference_t< TYPE > > strip_t
Remove any constness, volatile, and reference-ness from a type.
Definition types.hxx:80
constexpr bool is_null(TYPE const &value) noexcept
Is value null?
Definition strconv.hxx:515
zview generic_to_buf(char *begin, char *end, TYPE const &value)
Implement string_traits<TYPE>::to_buf by calling into_buf.
Definition strconv.hxx:587
T from_string(field const &value)
Convert a field's value to type T.
Definition field.hxx:548
constexpr bool is_unquoted_safe
Can we use this type in arrays and composite types without quoting them?
Definition strconv.hxx:555
constexpr bool is_sql_array
Does this type translate to an SQL array?
Definition strconv.hxx:539
format
Format code: is data text or binary?
Definition types.hxx:70
String traits for a forbidden type conversion.
Definition strconv.hxx:248
Helper class for defining enum conversions.
Definition strconv.hxx:361
Nullness traits describing a type which does not have a null value.
Definition strconv.hxx:113
static constexpr bool always_null
Are all values of this type null?
Definition strconv.hxx:131
static constexpr bool has_null
Does TYPE have a "built-in null value"?
Definition strconv.hxx:125
static constexpr bool is_null(TYPE const &) noexcept
Does a given value correspond to an SQL null value?
Definition strconv.hxx:138
Traits describing a type's "null value," if any.
Definition strconv.hxx:91
static bool is_null(TYPE const &value)
Is value a null?
static TYPE null()
Return a null value.
static bool has_null
Does this type have a null value?
Definition strconv.hxx:93
static bool always_null
Is this type always null?
Definition strconv.hxx:96
Traits class for use in string conversions.
Definition strconv.hxx:154
static TYPE from_string(std::string_view text)
Parse a string representation of a TYPE value.
static std::size_t size_buffer(TYPE const &value) noexcept
Estimate how much buffer space is needed to represent value.
static zview to_buf(char *begin, char *end, TYPE const &value)
Return a string_view representing value, plus terminating zero.
static constexpr bool converts_to_string
Is conversion from TYPE to strings supported?
Definition strconv.hxx:159
static char * into_buf(char *begin, char *end, TYPE const &value)
Write value's string representation into buffer at begin.
static constexpr bool converts_from_string
Is conversion from string_view to TYPE supported?
Definition strconv.hxx:165