libpqxx
The C++ client library for PostgreSQL
composite.hxx
Go to the documentation of this file.
1 #ifndef PQXX_COMPOSITE_HXX
2 #define PQXX_COMPOSITE_HXX
3 
4 #if !defined(PQXX_HEADER_PRE)
5 # error "Include libpqxx headers as <pqxx/header>, not <pqxx/header.hxx>."
6 #endif
7 
9 #include "pqxx/util.hxx"
10 
11 namespace pqxx
12 {
14 
33 template<typename... T>
34 inline void parse_composite(ctx c, std::string_view text, T &...fields)
35 {
36  static constexpr auto num_fields{sizeof...(T)};
37  static_assert(num_fields > 0);
38 
39  auto const data{std::data(text)};
40  auto const size{std::size(text)};
41  if (size == 0)
42  throw conversion_error{
43  "Cannot parse composite value from empty string.", c.loc};
44 
45  if (data[0] != '(')
46  throw conversion_error{
47  std::format("Invalid composite value string: '{}'.", text), c.loc};
48 
49  // clang-tidy rule bug:
50  // NOLINTBEGIN(misc-const-correctness)
51  std::size_t here{1};
52  std::size_t index{0};
53  // NOLINTEND(misc-const-correctness)
54  (pqxx::internal::specialize_parse_composite_field<T>(c)(
55  index, text, here, fields, num_fields - 1, c.loc),
56  ...);
57  if (here != std::size(text))
58  throw conversion_error{
60  "Composite value did not end at the closing parenthesis: '{}'.", text),
61  c.loc};
62  if (text[here - 1] != ')')
63  throw conversion_error{
64  std::format("Composite value did not end in parenthesis: '{}'.", text),
65  c.loc};
66 }
67 } // namespace pqxx
68 
69 
70 namespace pqxx::internal
71 {
72 constexpr char empty_composite_str[]{"()"};
73 } // namespace pqxx::internal
74 
75 
76 namespace pqxx
77 {
79 
81 template<typename... T>
82 [[nodiscard]] inline std::size_t
83 composite_size_buffer(T const &...fields) noexcept
84 {
85  constexpr auto num{sizeof...(fields)};
86 
87  // Size for a multi-field composite includes room for...
88  // + opening parenthesis
89  // + field budgets
90  // + separating comma per field
91  // - comma after final field
92  // + closing parenthesis
93  // + terminating zero
94 
95  if constexpr (num == 0)
96  return std::size(pqxx::internal::empty_composite_str);
97  else
98  return 1 + (pqxx::internal::size_composite_field_buffer(fields) + ...) +
99  num + 1;
100 }
101 
102 
104 
115 template<typename... T>
116 inline zview composite_into_buf(ctx c, std::span<char> buf, T const &...fields)
117 {
118  if (std::size(buf) < composite_size_buffer(fields...))
119  throw conversion_error{
120  "Buffer space may not be enough to represent composite value.", c.loc};
121 
122  constexpr auto num_fields{sizeof...(fields)};
123  if constexpr (num_fields == 0)
124  {
125  constexpr std::string_view empty{"()"};
126  return zview{
127  std::data(buf),
128  pqxx::internal::copy_chars<true>(empty, buf, 0, c.loc) - 1};
129  }
130 
131  std::size_t pos{0};
132  // C++26: Use buf.at().
133  buf[pos++] = '(';
134 
135  (pqxx::internal::write_composite_field<T>(buf, pos, fields, c), ...);
136 
137  // If we've got multiple fields, "backspace" that last comma.
138  if constexpr (num_fields > 1)
139  --pos;
140  // C++26: Use buf.at().
141  buf[pos++] = ')';
142  buf[pos] = '\0';
143  return zview{std::data(buf), pos};
144 }
145 
146 
148 template<typename... T>
149 [[deprecated(
150  "Pass conversion_context and std::span<char>, not two pointers.")]]
151 inline char *composite_into_buf(char *begin, char *end, T const &...fields)
152 {
153  auto const text{composite_into_buf(
154  {sl::current()}, std::span<char>{begin, end}, fields...)};
155  return begin + std::size(text);
156 }
157 } // namespace pqxx
158 #endif
Marker-type wrapper: zero-terminated std::string_view.
Definition: zview.hxx:55
Value conversion failed, e.g. when converting "Hello" to int.
Definition: except.hxx:612
Private namespace for libpqxx's internal use; do not access.
Definition: connection.cxx:333
PQXX_INLINE_COV std::size_t size_composite_field_buffer(T const &field)
Conservatively estimate buffer size needed for a composite field.
Definition: array-composite.hxx:352
constexpr char empty_composite_str[]
Definition: composite.hxx:72
The home of all libpqxx classes, functions, templates, etc.
Definition: array.cxx:26
void parse_composite(ctx c, std::string_view text, T &...fields)
Parse a string representation of a value of a composite type.
Definition: composite.hxx:34
std::size_t composite_size_buffer(T const &...fields) noexcept
Estimate the buffer size needed to represent a value of a composite type.
Definition: composite.hxx:83
conversion_context const & ctx
Convenience alias: const reference to a pqxx::conversion_context.
Definition: strconv.hxx:201
zview composite_into_buf(ctx c, std::span< char > buf, T const &...fields)
Render a series of values as a single composite SQL value.
Definition: composite.hxx:116
format
Format code: is data text or binary?
Definition: types.hxx:121