libpqxx  7.7.0
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 #include <array>
15 
16 #include "pqxx/internal/concat.hxx"
17 #include "pqxx/internal/statement_parameters.hxx"
18 #include "pqxx/types.hxx"
19 
20 
22 namespace pqxx::prepare
23 {
25 
42 template<typename IT>
43 [[deprecated("Use the params class instead.")]] constexpr inline auto
44 make_dynamic_params(IT begin, IT end)
45 {
46  return pqxx::internal::dynamic_params(begin, end);
47 }
48 
49 
51 
67 template<typename C>
68 [[deprecated("Use the params class instead.")]] constexpr inline auto
69 make_dynamic_params(C const &container)
70 {
71  using IT = typename C::const_iterator;
72 #include "pqxx/internal/ignore-deprecated-pre.hxx"
73  return pqxx::internal::dynamic_params<IT>{container};
74 #include "pqxx/internal/ignore-deprecated-post.hxx"
75 }
76 
77 
79 
96 template<typename C, typename ACCESSOR>
97 [[deprecated("Use the params class instead.")]] constexpr inline auto
98 make_dynamic_params(C &container, ACCESSOR accessor)
99 {
100  using IT = decltype(std::begin(container));
101 #include "pqxx/internal/ignore-deprecated-pre.hxx"
102  return pqxx::internal::dynamic_params<IT, ACCESSOR>{container, accessor};
103 #include "pqxx/internal/ignore-deprecated-post.hxx"
104 }
105 } // namespace pqxx::prepare
106 
107 
108 namespace pqxx
109 {
111 
121 template<typename COUNTER = unsigned int> class placeholders
122 {
123 public:
125  static inline constexpr unsigned int max_params{
126  (std::numeric_limits<COUNTER>::max)()};
127 
129  {
130  // C++20: constinit.
131  static constexpr auto initial{"$1\0"sv};
132  initial.copy(std::data(m_buf), std::size(initial));
133  }
134 
136 
139  zview view() const &noexcept { return zview{std::data(m_buf), m_len}; }
140 
142 
147  std::string get() const { return std::string(std::data(m_buf), m_len); }
148 
150  void next() &
151  {
152  if (m_current >= max_params)
153  throw range_error{pqxx::internal::concat(
154  "Too many parameters in one statement: limit is ", max_params, ".")};
155  ++m_current;
156  if (m_current % 10 == 0)
157  {
158  // Carry the 1. Don't get too clever for this relatively rare
159  // case, just rewrite the entire number. Leave the $ in place
160  // though.
161  char *const data{std::data(m_buf)};
162  char *const end{string_traits<COUNTER>::into_buf(
163  data + 1, data + std::size(m_buf), m_current)};
164  // (Subtract because we don't include the trailing zero.)
165  m_len = check_cast<COUNTER>(end - data, "placeholders counter") - 1;
166  }
167  else
168  {
169  PQXX_LIKELY
170  // Shortcut for the common case: just increment that last digit.
171  ++m_buf[m_len - 1];
172  }
173  }
174 
176  COUNTER count() const noexcept { return m_current; }
177 
178 private:
180  COUNTER m_current = 1;
181 
183  COUNTER m_len = 2;
184 
186 
193  std::array<char, std::numeric_limits<COUNTER>::digits10 + 3> m_buf;
194 };
195 
196 
198 
213 class PQXX_LIBEXPORT params
214 {
215 public:
216  params() = default;
217 
219  template<typename... Args> constexpr params(Args &&...args)
220  {
221  reserve(sizeof...(args));
222  append_pack(std::forward<Args>(args)...);
223  }
224 
226 
232  void reserve(std::size_t n) &;
233 
235  [[nodiscard]] auto size() const noexcept { return m_params.size(); }
236 
237  // C++20: Use the vector's ssize() directly and go noexcept.
239 
244  [[nodiscard]] auto ssize() const { return pqxx::internal::ssize(m_params); }
245 
247  void append() &;
248 
250 
253  void append(zview) &;
254 
256 
259  void append(std::string const &) &;
260 
262  void append(std::string &&) &;
263 
265 
268  void append(std::basic_string_view<std::byte>) &;
269 
271 
275  void append(std::basic_string<std::byte> const &) &;
276 
277 #if defined(PQXX_HAVE_CONCEPTS)
278 
282  template<binary DATA> void append(DATA const &data) &
283  {
284  append(
285  std::basic_string_view<std::byte>{std::data(data), std::size(data)});
286  }
287 #endif // PQXX_HAVE_CONCEPTS
288 
290  void append(std::basic_string<std::byte> &&) &;
291 
293 
296  void append(binarystring const &value) &;
297 
299  template<typename IT, typename ACCESSOR>
300  void append(pqxx::internal::dynamic_params<IT, ACCESSOR> const &value) &
301  {
302  for (auto &param : value) append(value.access(param));
303  }
304 
305  void append(params const &value) &;
306 
307  void append(params &&value) &;
308 
311  template<typename TYPE> void append(TYPE const &value) &
312  {
313  // TODO: Pool storage for multiple string conversions in one buffer?
314  if constexpr (nullness<strip_t<TYPE>>::always_null)
315  {
316  ignore_unused(value);
317  m_params.emplace_back();
318  }
319  else if (is_null(value))
320  {
321  m_params.emplace_back();
322  }
323  else
324  {
325  m_params.emplace_back(entry{to_string(value)});
326  }
327  }
328 
330  template<PQXX_RANGE_ARG RANGE> void append_multi(RANGE const &range) &
331  {
332 #if defined(PQXX_HAVE_CONCEPTS)
333  if constexpr (std::ranges::sized_range<RANGE>)
334  reserve(std::size(*this) + std::size(range));
335 #endif
336  for (auto &value : range) append(value);
337  }
338 
340 
349  pqxx::internal::c_params make_c_params() const;
350 
351 private:
353  template<typename Arg, typename... More>
354  void append_pack(Arg &&arg, More &&...args)
355  {
356  this->append(std::forward<Arg>(arg));
357  // Recurse for remaining args.
358  append_pack(std::forward<More>(args)...);
359  }
360 
362  void append_pack() {}
363 
364  // The way we store a parameter depends on whether it's binary or text
365  // (most types are text), and whether we're responsible for storing the
366  // contents.
367  using entry = std::variant<
368  std::nullptr_t, zview, std::string, std::basic_string_view<std::byte>,
369  std::basic_string<std::byte>>;
370  std::vector<entry> m_params;
371 
372  // C++20: constinit.
373  static constexpr std::string_view s_overflow{
374  "Statement parameter length overflow."sv};
375 };
376 } // namespace pqxx
377 #endif
Generate parameter placeholders for use in an SQL statement.
Definition: params.hxx:121
Binary data corresponding to PostgreSQL&#39;s "BYTEA" binary-string type.
Definition: binarystring.hxx:54
std::remove_cv_t< std::remove_reference_t< TYPE > > strip_t
Remove any constness, volatile, and reference-ness from a type.
Definition: types.hxx:87
Definition: params.hxx:22
auto ssize(T const &c)
Transitional: std::ssize(), or custom implementation if not available.
Definition: util.hxx:439
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:136
bool is_null(TYPE const &value) noexcept
Is value null?
Definition: strconv.hxx:364
zview view() const &noexcept
Read an ephemeral version of the current placeholder text.
Definition: params.hxx:139
constexpr auto make_dynamic_params(IT begin, IT end)
Pass a number of statement parameters only known at runtime.
Definition: params.hxx:44
COUNTER count() const noexcept
Return the current placeholder number. The initial placeholder is 1.
Definition: params.hxx:176
auto ssize() const
Get the number of parameters (signed).
Definition: params.hxx:244
void append_multi(RANGE const &range) &
Append all elements of range as parameters.
Definition: params.hxx:330
constexpr params(Args &&...args)
Pre-populate a params with args. Feel free to add more later.
Definition: params.hxx:219
Build a parameter list for a parameterised or prepared statement.
Definition: params.hxx:213
void append(TYPE const &value) &
Definition: params.hxx:311
static char * into_buf(char *begin, char *end, TYPE const &value)
Write value&#39;s string representation into buffer at begin.
void append(pqxx::internal::dynamic_params< IT, ACCESSOR > const &value) &
Append all parameters from value.
Definition: params.hxx:300
void ignore_unused(T &&...)
Suppress compiler warning about an unused item.
Definition: util.hxx:128
Marker-type wrapper: zero-terminated std::string_view.
Definition: zview.hxx:37
A C++ equivalent to PostgreSQL&#39;s range types.
Definition: range.hxx:198
void next() &
Move on to the next parameter.
Definition: params.hxx:150
placeholders()
Definition: params.hxx:128
Traits describing a type&#39;s "null value," if any.
Definition: strconv.hxx:88
auto size() const noexcept
Get the number of parameters currently in this params.
Definition: params.hxx:235
The home of all libpqxx classes, functions, templates, etc.
Definition: array.hxx:22
std::string to_string(field const &value)
Convert a field to a string.
Definition: result.cxx:528
Something is out of range, similar to std::out_of_range.
Definition: except.hxx:189