libpqxx
The C++ client library for PostgreSQL
params.hxx
1 /* Helpers for prepared statements and parameterised statements.
2  *
3  * See @ref connection and @ref transaction_base for more.
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_PARAMS
12 #define PQXX_H_PARAMS
13 
14 #if !defined(PQXX_HEADER_PRE)
15 # error "Include libpqxx headers as <pqxx/header>, not <pqxx/header.hxx>."
16 #endif
17 
18 #include <array>
19 
20 #include "pqxx/internal/concat.hxx"
21 #include "pqxx/internal/statement_parameters.hxx"
22 #include "pqxx/types.hxx"
23 
24 
25 namespace pqxx
26 {
28 
32 class PQXX_LIBEXPORT params
33 {
34 public:
35  params() = default;
36 
38  template<typename... Args> constexpr params(Args &&...args)
39  {
40  reserve(sizeof...(args));
41  append_pack(std::forward<Args>(args)...);
42  }
43 
45 
51  void reserve(std::size_t n) &;
52 
53  // C++20: constexpr.
55  [[nodiscard]] auto size() const noexcept { return m_params.size(); }
56 
57  // C++20: Use the vector's ssize() directly and go noexcept+constexpr.
59 
64  [[nodiscard]] auto ssize() const { return pqxx::internal::ssize(m_params); }
65 
67  void append() &;
68 
70 
73  void append(zview) &;
74 
76 
79  void append(std::string const &) &;
80 
82  void append(std::string &&) &;
83 
85 
88  void append(bytes_view) &;
89 
91 
94  void append(bytes const &) &;
95 
96 #if defined(PQXX_HAVE_CONCEPTS) && defined(PQXX_HAVE_RANGES)
97 
101  template<binary DATA> void append(DATA const &data) &
102  {
103  append(bytes_view{std::data(data), std::size(data)});
104  }
105 #endif // PQXX_HAVE_CONCEPTS
106 
108  void append(bytes &&) &;
109 
111 
114  void append(binarystring const &value) &;
115 
117  template<typename IT, typename ACCESSOR>
119  {
120  for (auto &param : value) append(value.access(param));
121  }
122 
123  void append(params const &value) &;
124 
125  void append(params &&value) &;
126 
129  template<typename TYPE> void append(TYPE const &value) &
130  {
131  // TODO: Pool storage for multiple string conversions in one buffer?
132  if constexpr (nullness<strip_t<TYPE>>::always_null)
133  {
134  ignore_unused(value);
135  m_params.emplace_back();
136  }
137  else if (is_null(value))
138  {
139  m_params.emplace_back();
140  }
141  else
142  {
143  m_params.emplace_back(entry{to_string(value)});
144  }
145  }
146 
148  template<PQXX_RANGE_ARG RANGE> void append_multi(RANGE const &range) &
149  {
150 #if defined(PQXX_HAVE_CONCEPTS) && defined(PQXX_HAVE_RANGES)
151  if constexpr (std::ranges::sized_range<RANGE>)
152  reserve(std::size(*this) + std::size(range));
153 #endif
154  for (auto &value : range) append(value);
155  }
156 
158 
167  pqxx::internal::c_params make_c_params() const;
168 
169 private:
171  template<typename Arg, typename... More>
172  void append_pack(Arg &&arg, More &&...args)
173  {
174  this->append(std::forward<Arg>(arg));
175  // Recurse for remaining args.
176  append_pack(std::forward<More>(args)...);
177  }
178 
180  constexpr void append_pack() noexcept {}
181 
182  // The way we store a parameter depends on whether it's binary or text
183  // (most types are text), and whether we're responsible for storing the
184  // contents.
185  using entry =
186  std::variant<std::nullptr_t, zview, std::string, bytes_view, bytes>;
187  std::vector<entry> m_params;
188 
189  static constexpr std::string_view s_overflow{
190  "Statement parameter length overflow."sv};
191 };
192 
193 
195 
205 template<typename COUNTER = unsigned int> class placeholders
206 {
207 public:
209  static inline constexpr unsigned int max_params{
210  (std::numeric_limits<COUNTER>::max)()};
211 
212  placeholders()
213  {
214  static constexpr auto initial{"$1\0"sv};
215  initial.copy(std::data(m_buf), std::size(initial));
216  }
217 
219 
222  constexpr zview view() const & noexcept
223  {
224  return zview{std::data(m_buf), m_len};
225  }
226 
228 
233  std::string get() const { return std::string(std::data(m_buf), m_len); }
234 
236  void next() &
237  {
238  if (m_current >= max_params)
240  "Too many parameters in one statement: limit is ", max_params, ".")};
241  PQXX_ASSUME(m_current > 0);
242  ++m_current;
243  if (m_current % 10 == 0)
244  {
245  // Carry the 1. Don't get too clever for this relatively rare
246  // case, just rewrite the entire number. Leave the $ in place
247  // though.
248  char *const data{std::data(m_buf)};
249  char *const end{string_traits<COUNTER>::into_buf(
250  data + 1, data + std::size(m_buf), m_current)};
251  // (Subtract because we don't include the trailing zero.)
252  m_len = check_cast<COUNTER>(end - data, "placeholders counter") - 1;
253  }
254  else
255  {
256  PQXX_LIKELY
257  // Shortcut for the common case: just increment that last digit.
258  ++m_buf[m_len - 1];
259  }
260  }
261 
263  COUNTER count() const noexcept { return m_current; }
264 
265 private:
267  COUNTER m_current = 1;
268 
270  COUNTER m_len = 2;
271 
273 
280  std::array<char, std::numeric_limits<COUNTER>::digits10 + 3> m_buf;
281 };
282 } // namespace pqxx
283 
284 
286 namespace pqxx::prepare
287 {
289 template<typename IT>
290 [[deprecated("Use the params class instead.")]] constexpr inline auto
291 make_dynamic_params(IT begin, IT end)
292 {
293  return pqxx::internal::dynamic_params(begin, end);
294 }
295 
296 
298 template<typename C>
299 [[deprecated("Use the params class instead.")]] constexpr inline auto
300 make_dynamic_params(C const &container)
301 {
302  using IT = typename C::const_iterator;
303 #include "pqxx/internal/ignore-deprecated-pre.hxx"
304  return pqxx::internal::dynamic_params<IT>{container};
305 #include "pqxx/internal/ignore-deprecated-post.hxx"
306 }
307 
308 
310 template<typename C, typename ACCESSOR>
311 [[deprecated("Use the params class instead.")]] constexpr inline auto
312 make_dynamic_params(C &container, ACCESSOR accessor)
313 {
314  using IT = decltype(std::begin(container));
315 #include "pqxx/internal/ignore-deprecated-pre.hxx"
316  return pqxx::internal::dynamic_params<IT, ACCESSOR>{container, accessor};
317 #include "pqxx/internal/ignore-deprecated-post.hxx"
318 }
319 } // namespace pqxx::prepare
320 #endif
std::string concat(TYPE...item)
Efficiently combine a bunch of items into one big string.
Definition: concat.hxx:31
Marker-type wrapper: zero-terminated std::string_view.
Definition: zview.hxx:37
void append(TYPE const &value)&
Definition: params.hxx:129
auto ssize(T const &c)
Transitional: std::ssize(), or custom implementation if not available.
Definition: util.hxx:555
TO check_cast(FROM value, std::string_view description)
Cast a numeric value to another type, or throw if it underflows/overflows.
Definition: util.hxx:153
Definition: statement_parameters.hxx:35
constexpr auto make_dynamic_params(IT begin, IT end)
Definition: params.hxx:291
auto ssize() const
Get the number of parameters (signed).
Definition: params.hxx:64
Something is out of range, similar to std::out_of_range.
Definition: except.hxx:325
constexpr zview view() const &noexcept
Read an ephemeral version of the current placeholder text.
Definition: params.hxx:222
PQXX_LIBEXPORT std::string to_string(field const &value)
Convert a field to a string.
A C++ equivalent to PostgreSQL's range types.
Definition: range.hxx:239
constexpr bool is_null(TYPE const &value) noexcept
Is value null?
Definition: strconv.hxx:515
Definition: params.hxx:286
Internal type: encode statement parameters.
Definition: statement_parameters.hxx:94
Build a parameter list for a parameterised or prepared statement.
Definition: params.hxx:32
COUNTER count() const noexcept
Return the current placeholder number. The initial placeholder is 1.
Definition: params.hxx:263
auto size() const noexcept
Get the number of parameters currently in this params.
Definition: params.hxx:55
The home of all libpqxx classes, functions, templates, etc.
Definition: array.cxx:26
constexpr void ignore_unused(T &&...) noexcept
Suppress compiler warning about an unused item.
Definition: util.hxx:144
std::conditional< has_generic_bytes_char_traits, std::basic_string< std::byte >, std::basic_string< std::byte, byte_char_traits >>::type bytes
Type alias for a container containing bytes.
Definition: util.hxx:375
void append(pqxx::internal::dynamic_params< IT, ACCESSOR > const &value)&
Append all parameters from value.
Definition: params.hxx:118
void next()&
Move on to the next parameter.
Definition: params.hxx:236
void append_multi(RANGE const &range)&
Append all elements of range as parameters.
Definition: params.hxx:148
Traits describing a type's "null value," if any.
Definition: strconv.hxx:90
static char * into_buf(char *begin, char *end, TYPE const &value)
Write value's string representation into buffer at begin.
static constexpr unsigned int max_params
Maximum number of parameters we support.
Definition: params.hxx:209
std::conditional< has_generic_bytes_char_traits, std::basic_string_view< std::byte >, std::basic_string_view< std::byte, byte_char_traits >>::type bytes_view
Type alias for a view of bytes.
Definition: util.hxx:385
Generate parameter placeholders for use in an SQL statement.
Definition: params.hxx:205
constexpr params(Args &&...args)
Pre-populate a params with args. Feel free to add more later.
Definition: params.hxx:38
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