libpqxx  7.7.1
params.hxx
1 /* Helpers for prepared statements and parameterised statements.
2  *
3  * See the connection class for more about such statements.
4  *
5  * Copyright (c) 2000-2022, 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 
26 namespace pqxx::prepare
27 {
29 
46 template<typename IT>
47 [[deprecated("Use the params class instead.")]] constexpr inline auto
48 make_dynamic_params(IT begin, IT end)
49 {
50  return pqxx::internal::dynamic_params(begin, end);
51 }
52 
53 
55 
71 template<typename C>
72 [[deprecated("Use the params class instead.")]] constexpr inline auto
73 make_dynamic_params(C const &container)
74 {
75  using IT = typename C::const_iterator;
76 #include "pqxx/internal/ignore-deprecated-pre.hxx"
77  return pqxx::internal::dynamic_params<IT>{container};
78 #include "pqxx/internal/ignore-deprecated-post.hxx"
79 }
80 
81 
83 
100 template<typename C, typename ACCESSOR>
101 [[deprecated("Use the params class instead.")]] constexpr inline auto
102 make_dynamic_params(C &container, ACCESSOR accessor)
103 {
104  using IT = decltype(std::begin(container));
105 #include "pqxx/internal/ignore-deprecated-pre.hxx"
106  return pqxx::internal::dynamic_params<IT, ACCESSOR>{container, accessor};
107 #include "pqxx/internal/ignore-deprecated-post.hxx"
108 }
109 } // namespace pqxx::prepare
110 
111 
112 namespace pqxx
113 {
115 
125 template<typename COUNTER = unsigned int> class placeholders
126 {
127 public:
129  static inline constexpr unsigned int max_params{
130  (std::numeric_limits<COUNTER>::max)()};
131 
133  {
134  static constexpr auto initial{"$1\0"sv};
135  initial.copy(std::data(m_buf), std::size(initial));
136  }
137 
139 
142  constexpr zview view() const &noexcept
143  {
144  return zview{std::data(m_buf), m_len};
145  }
146 
148 
153  std::string get() const { return std::string(std::data(m_buf), m_len); }
154 
156  void next() &
157  {
158  if (m_current >= max_params)
159  throw range_error{pqxx::internal::concat(
160  "Too many parameters in one statement: limit is ", max_params, ".")};
161  ++m_current;
162  if (m_current % 10 == 0)
163  {
164  // Carry the 1. Don't get too clever for this relatively rare
165  // case, just rewrite the entire number. Leave the $ in place
166  // though.
167  char *const data{std::data(m_buf)};
168  char *const end{string_traits<COUNTER>::into_buf(
169  data + 1, data + std::size(m_buf), m_current)};
170  // (Subtract because we don't include the trailing zero.)
171  m_len = check_cast<COUNTER>(end - data, "placeholders counter") - 1;
172  }
173  else
174  {
175  PQXX_LIKELY
176  // Shortcut for the common case: just increment that last digit.
177  ++m_buf[m_len - 1];
178  }
179  }
180 
182  COUNTER count() const noexcept { return m_current; }
183 
184 private:
186  COUNTER m_current = 1;
187 
189  COUNTER m_len = 2;
190 
192 
199  std::array<char, std::numeric_limits<COUNTER>::digits10 + 3> m_buf;
200 };
201 
202 
204 
219 class PQXX_LIBEXPORT params
220 {
221 public:
222  params() = default;
223 
225  template<typename... Args> constexpr params(Args &&...args)
226  {
227  reserve(sizeof...(args));
228  append_pack(std::forward<Args>(args)...);
229  }
230 
232 
238  void reserve(std::size_t n) &;
239 
240  // C++20: constexpr.
242  [[nodiscard]] auto size() const noexcept { return m_params.size(); }
243 
244  // C++20: Use the vector's ssize() directly and go noexcept+constexpr.
246 
251  [[nodiscard]] auto ssize() const { return pqxx::internal::ssize(m_params); }
252 
254  void append() &;
255 
257 
260  void append(zview) &;
261 
263 
266  void append(std::string const &) &;
267 
269  void append(std::string &&) &;
270 
272 
275  void append(std::basic_string_view<std::byte>) &;
276 
278 
282  void append(std::basic_string<std::byte> const &) &;
283 
284 #if defined(PQXX_HAVE_CONCEPTS)
285 
289  template<binary DATA> void append(DATA const &data) &
290  {
291  append(
292  std::basic_string_view<std::byte>{std::data(data), std::size(data)});
293  }
294 #endif // PQXX_HAVE_CONCEPTS
295 
297  void append(std::basic_string<std::byte> &&) &;
298 
300 
303  void append(binarystring const &value) &;
304 
306  template<typename IT, typename ACCESSOR>
307  void append(pqxx::internal::dynamic_params<IT, ACCESSOR> const &value) &
308  {
309  for (auto &param : value) append(value.access(param));
310  }
311 
312  void append(params const &value) &;
313 
314  void append(params &&value) &;
315 
318  template<typename TYPE> void append(TYPE const &value) &
319  {
320  // TODO: Pool storage for multiple string conversions in one buffer?
321  if constexpr (nullness<strip_t<TYPE>>::always_null)
322  {
323  ignore_unused(value);
324  m_params.emplace_back();
325  }
326  else if (is_null(value))
327  {
328  m_params.emplace_back();
329  }
330  else
331  {
332  m_params.emplace_back(entry{to_string(value)});
333  }
334  }
335 
337  template<PQXX_RANGE_ARG RANGE> void append_multi(RANGE const &range) &
338  {
339 #if defined(PQXX_HAVE_CONCEPTS)
340  if constexpr (std::ranges::sized_range<RANGE>)
341  reserve(std::size(*this) + std::size(range));
342 #endif
343  for (auto &value : range) append(value);
344  }
345 
347 
356  pqxx::internal::c_params make_c_params() const;
357 
358 private:
360  template<typename Arg, typename... More>
361  void append_pack(Arg &&arg, More &&...args)
362  {
363  this->append(std::forward<Arg>(arg));
364  // Recurse for remaining args.
365  append_pack(std::forward<More>(args)...);
366  }
367 
369  constexpr void append_pack() noexcept {}
370 
371  // The way we store a parameter depends on whether it's binary or text
372  // (most types are text), and whether we're responsible for storing the
373  // contents.
374  using entry = std::variant<
375  std::nullptr_t, zview, std::string, std::basic_string_view<std::byte>,
376  std::basic_string<std::byte>>;
377  std::vector<entry> m_params;
378 
379  static constexpr std::string_view s_overflow{
380  "Statement parameter length overflow."sv};
381 };
382 } // namespace pqxx
383 #endif
auto size() const noexcept
Get the number of parameters currently in this params.
Definition: params.hxx:242
Something is out of range, similar to std::out_of_range.
Definition: except.hxx:201
COUNTER count() const noexcept
Return the current placeholder number. The initial placeholder is 1.
Definition: params.hxx:182
The home of all libpqxx classes, functions, templates, etc.
Definition: array.hxx:26
auto ssize(T const &c)
Transitional: std::ssize(), or custom implementation if not available.
Definition: util.hxx:446
Definition: params.hxx:26
void append(TYPE const &value) &
Definition: params.hxx:318
Generate parameter placeholders for use in an SQL statement.
Definition: params.hxx:125
std::string to_string(field const &value)
Convert a field to a string.
Definition: result.cxx:533
constexpr auto make_dynamic_params(IT begin, IT end)
Pass a number of statement parameters only known at runtime.
Definition: params.hxx:48
auto ssize() const
Get the number of parameters (signed).
Definition: params.hxx:251
void append_multi(RANGE const &range) &
Append all elements of range as parameters.
Definition: params.hxx:337
constexpr void ignore_unused(T &&...) noexcept
Suppress compiler warning about an unused item.
Definition: util.hxx:136
constexpr params(Args &&...args)
Pre-populate a params with args. Feel free to add more later.
Definition: params.hxx:225
void append(pqxx::internal::dynamic_params< IT, ACCESSOR > const &value) &
Append all parameters from value.
Definition: params.hxx:307
std::remove_cv_t< std::remove_reference_t< TYPE > > strip_t
Remove any constness, volatile, and reference-ness from a type.
Definition: types.hxx:91
Marker-type wrapper: zero-terminated std::string_view.
Definition: zview.hxx:37
A C++ equivalent to PostgreSQL&#39;s range types.
Definition: range.hxx:215
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:145
Binary data corresponding to PostgreSQL&#39;s "BYTEA" binary-string type.
Definition: binarystring.hxx:58
void next() &
Move on to the next parameter.
Definition: params.hxx:156
Traits describing a type&#39;s "null value," if any.
Definition: strconv.hxx:92
constexpr bool is_null(TYPE const &value) noexcept
Is value null?
Definition: strconv.hxx:367
placeholders()
Definition: params.hxx:132
static char * into_buf(char *begin, char *end, TYPE const &value)
Write value&#39;s string representation into buffer at begin.
constexpr zview view() const &noexcept
Read an ephemeral version of the current placeholder text.
Definition: params.hxx:142
Build a parameter list for a parameterised or prepared statement.
Definition: params.hxx:219