libpqxx  7.9.0
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-2024, 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 
45 class PQXX_LIBEXPORT params
46 {
47 public:
48  params() = default;
49 
51  template<typename... Args> constexpr params(Args &&...args)
52  {
53  reserve(sizeof...(args));
54  append_pack(std::forward<Args>(args)...);
55  }
56 
58 
64  void reserve(std::size_t n) &;
65 
66  // C++20: constexpr.
68  [[nodiscard]] auto size() const noexcept { return m_params.size(); }
69 
70  // C++20: Use the vector's ssize() directly and go noexcept+constexpr.
72 
77  [[nodiscard]] auto ssize() const { return pqxx::internal::ssize(m_params); }
78 
80  void append() &;
81 
83 
86  void append(zview) &;
87 
89 
92  void append(std::string const &) &;
93 
95  void append(std::string &&) &;
96 
98 
101  void append(bytes_view) &;
102 
104 
107  void append(bytes const &) &;
108 
109 #if defined(PQXX_HAVE_CONCEPTS)
111 
114  template<binary DATA> void append(DATA const &data) &
115  {
116  append(bytes_view{std::data(data), std::size(data)});
117  }
118 #endif // PQXX_HAVE_CONCEPTS
119 
121  void append(bytes &&) &;
122 
124 
127  void append(binarystring const &value) &;
128 
130  template<typename IT, typename ACCESSOR>
131  void append(pqxx::internal::dynamic_params<IT, ACCESSOR> const &value) &
132  {
133  for (auto &param : value) append(value.access(param));
134  }
135 
136  void append(params const &value) &;
137 
138  void append(params &&value) &;
139 
142  template<typename TYPE> void append(TYPE const &value) &
143  {
144  // TODO: Pool storage for multiple string conversions in one buffer?
145  if constexpr (nullness<strip_t<TYPE>>::always_null)
146  {
147  ignore_unused(value);
148  m_params.emplace_back();
149  }
150  else if (is_null(value))
151  {
152  m_params.emplace_back();
153  }
154  else
155  {
156  m_params.emplace_back(entry{to_string(value)});
157  }
158  }
159 
161  template<PQXX_RANGE_ARG RANGE> void append_multi(RANGE const &range) &
162  {
163 #if defined(PQXX_HAVE_CONCEPTS)
164  if constexpr (std::ranges::sized_range<RANGE>)
165  reserve(std::size(*this) + std::size(range));
166 #endif
167  for (auto &value : range) append(value);
168  }
169 
171 
180  pqxx::internal::c_params make_c_params() const;
181 
182 private:
184  template<typename Arg, typename... More>
185  void append_pack(Arg &&arg, More &&...args)
186  {
187  this->append(std::forward<Arg>(arg));
188  // Recurse for remaining args.
189  append_pack(std::forward<More>(args)...);
190  }
191 
193  constexpr void append_pack() noexcept {}
194 
195  // The way we store a parameter depends on whether it's binary or text
196  // (most types are text), and whether we're responsible for storing the
197  // contents.
198  using entry =
199  std::variant<std::nullptr_t, zview, std::string, bytes_view, bytes>;
200  std::vector<entry> m_params;
201 
202  static constexpr std::string_view s_overflow{
203  "Statement parameter length overflow."sv};
204 };
205 
206 
208 
218 template<typename COUNTER = unsigned int> class placeholders
219 {
220 public:
222  static inline constexpr unsigned int max_params{
223  (std::numeric_limits<COUNTER>::max)()};
224 
226  {
227  static constexpr auto initial{"$1\0"sv};
228  initial.copy(std::data(m_buf), std::size(initial));
229  }
230 
232 
235  constexpr zview view() const & noexcept
236  {
237  return zview{std::data(m_buf), m_len};
238  }
239 
241 
246  std::string get() const { return std::string(std::data(m_buf), m_len); }
247 
249  void next() &
250  {
251  if (m_current >= max_params)
252  throw range_error{pqxx::internal::concat(
253  "Too many parameters in one statement: limit is ", max_params, ".")};
254  ++m_current;
255  if (m_current % 10 == 0)
256  {
257  // Carry the 1. Don't get too clever for this relatively rare
258  // case, just rewrite the entire number. Leave the $ in place
259  // though.
260  char *const data{std::data(m_buf)};
261  char *const end{string_traits<COUNTER>::into_buf(
262  data + 1, data + std::size(m_buf), m_current)};
263  // (Subtract because we don't include the trailing zero.)
264  m_len = check_cast<COUNTER>(end - data, "placeholders counter") - 1;
265  }
266  else
267  {
268  PQXX_LIKELY
269  // Shortcut for the common case: just increment that last digit.
270  ++m_buf[m_len - 1];
271  }
272  }
273 
275  COUNTER count() const noexcept { return m_current; }
276 
277 private:
279  COUNTER m_current = 1;
280 
282  COUNTER m_len = 2;
283 
285 
292  std::array<char, std::numeric_limits<COUNTER>::digits10 + 3> m_buf;
293 };
294 } // namespace pqxx
295 
296 
298 namespace pqxx::prepare
299 {
301 
318 template<typename IT>
319 [[deprecated("Use the params class instead.")]] constexpr inline auto
320 make_dynamic_params(IT begin, IT end)
321 {
322  return pqxx::internal::dynamic_params(begin, end);
323 }
324 
325 
327 
343 template<typename C>
344 [[deprecated("Use the params class instead.")]] constexpr inline auto
345 make_dynamic_params(C const &container)
346 {
347  using IT = typename C::const_iterator;
348 #include "pqxx/internal/ignore-deprecated-pre.hxx"
349  return pqxx::internal::dynamic_params<IT>{container};
350 #include "pqxx/internal/ignore-deprecated-post.hxx"
351 }
352 
353 
355 
372 template<typename C, typename ACCESSOR>
373 [[deprecated("Use the params class instead.")]] constexpr inline auto
374 make_dynamic_params(C &container, ACCESSOR accessor)
375 {
376  using IT = decltype(std::begin(container));
377 #include "pqxx/internal/ignore-deprecated-pre.hxx"
378  return pqxx::internal::dynamic_params<IT, ACCESSOR>{container, accessor};
379 #include "pqxx/internal/ignore-deprecated-post.hxx"
380 }
381 } // namespace pqxx::prepare
382 #endif
The home of all libpqxx classes, functions, templates, etc.
Definition: array.hxx:33
std::remove_cv_t< std::remove_reference_t< TYPE > > strip_t
Remove any constness, volatile, and reference-ness from a type.
Definition: types.hxx:78
constexpr void ignore_unused(T &&...) noexcept
Suppress compiler warning about an unused item.
Definition: util.hxx:142
constexpr bool is_null(TYPE const &value) noexcept
Is value null?
Definition: strconv.hxx:513
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:373
std::string to_string(field const &value)
Convert a field to a string.
Definition: result.cxx:566
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:383
auto ssize(T const &c)
Transitional: std::ssize(), or custom implementation if not available.
Definition: util.hxx:553
Definition: params.hxx:299
constexpr auto make_dynamic_params(IT begin, IT end)
Pass a number of statement parameters only known at runtime.
Definition: params.hxx:320
Something is out of range, similar to std::out_of_range.
Definition: except.hxx:326
Build a parameter list for a parameterised or prepared statement.
Definition: params.hxx:46
auto size() const noexcept
Get the number of parameters currently in this params.
Definition: params.hxx:68
void append_multi(RANGE const &range) &
Append all elements of range as parameters.
Definition: params.hxx:161
void append(TYPE const &value) &
Definition: params.hxx:142
params()=default
auto ssize() const
Get the number of parameters (signed).
Definition: params.hxx:77
void append(pqxx::internal::dynamic_params< IT, ACCESSOR > const &value) &
Append all parameters from value.
Definition: params.hxx:131
constexpr params(Args &&...args)
Pre-populate a params with args. Feel free to add more later.
Definition: params.hxx:51
Generate parameter placeholders for use in an SQL statement.
Definition: params.hxx:219
static constexpr unsigned int max_params
Maximum number of parameters we support.
Definition: params.hxx:222
COUNTER count() const noexcept
Return the current placeholder number. The initial placeholder is 1.
Definition: params.hxx:275
std::string get() const
Read the current placeholder text, as a std::string.
Definition: params.hxx:246
placeholders()
Definition: params.hxx:225
constexpr zview view() const &noexcept
Read an ephemeral version of the current placeholder text.
Definition: params.hxx:235
void next() &
Move on to the next parameter.
Definition: params.hxx:249
A C++ equivalent to PostgreSQL's range types.
Definition: range.hxx:240
Traits describing a type's "null value," if any.
Definition: strconv.hxx:91
static char * into_buf(char *begin, char *end, TYPE const &value)
Write value's string representation into buffer at begin.
Marker-type wrapper: zero-terminated std::string_view.
Definition: zview.hxx:38