libpqxx
The C++ client library for PostgreSQL
Loading...
Searching...
No Matches
params.hxx
Go to the documentation of this file.
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#include <variant>
20
23#include "pqxx/types.hxx"
24
25
26namespace pqxx
27{
29
33class PQXX_LIBEXPORT params
34{
35public:
36 params() = default;
37
39 template<typename... Args> constexpr params(Args &&...args)
40 {
41 reserve(sizeof...(args));
42 append_pack(std::forward<Args>(args)...);
43 }
44
46
52 void reserve(std::size_t n) &;
53
54 // C++20: constexpr.
56 [[nodiscard]] auto size() const noexcept { return m_params.size(); }
57
58 // C++20: Use the vector's ssize() directly and go noexcept+constexpr.
60
65 [[nodiscard]] auto ssize() const { return pqxx::internal::ssize(m_params); }
66
68 void append() &;
69
71
74 void append(zview) &;
75
77
80 void append(std::string const &) &;
81
83 void append(std::string &&) &;
84
86
89 void append(bytes_view) &;
90
92
95 void append(bytes const &) &;
96
97#if defined(PQXX_HAVE_CONCEPTS) && defined(PQXX_HAVE_RANGES)
99
102 template<binary DATA> void append(DATA const &data) &
103 {
104 append(bytes_view{std::data(data), std::size(data)});
105 }
106#endif // PQXX_HAVE_CONCEPTS
107
109 void append(bytes &&) &;
110
112
115 void append(binarystring const &value) &;
116
118 template<typename IT, typename ACCESSOR>
119 void append(pqxx::internal::dynamic_params<IT, ACCESSOR> const &value) &
120 {
121 for (auto &param : value) append(value.access(param));
122 }
123
124 void append(params const &value) &;
125
126 void append(params &&value) &;
127
130 template<typename TYPE> void append(TYPE const &value) &
131 {
132 // TODO: Pool storage for multiple string conversions in one buffer?
133 if constexpr (nullness<strip_t<TYPE>>::always_null)
134 {
135 ignore_unused(value);
136 m_params.emplace_back();
137 }
138 else if (is_null(value))
139 {
140 m_params.emplace_back();
141 }
142 else
143 {
144 m_params.emplace_back(entry{to_string(value)});
145 }
146 }
147
149 template<PQXX_RANGE_ARG RANGE> void append_multi(RANGE const &range) &
150 {
151#if defined(PQXX_HAVE_CONCEPTS) && defined(PQXX_HAVE_RANGES)
152 if constexpr (std::ranges::sized_range<RANGE>)
153 reserve(std::size(*this) + std::size(range));
154#endif
155 for (auto &value : range) append(value);
156 }
157
159
168 pqxx::internal::c_params make_c_params() const;
169
170private:
172 template<typename Arg, typename... More>
173 void append_pack(Arg &&arg, More &&...args)
174 {
175 this->append(std::forward<Arg>(arg));
176 // Recurse for remaining args.
177 append_pack(std::forward<More>(args)...);
178 }
179
181 constexpr void append_pack() noexcept {}
182
183 // The way we store a parameter depends on whether it's binary or text
184 // (most types are text), and whether we're responsible for storing the
185 // contents.
186 using entry =
187 std::variant<std::nullptr_t, zview, std::string, bytes_view, bytes>;
188 std::vector<entry> m_params;
189
190 static constexpr std::string_view s_overflow{
191 "Statement parameter length overflow."sv};
192};
193
194
196
206template<typename COUNTER = unsigned int> class placeholders
207{
208public:
210 static inline constexpr unsigned int max_params{
211 (std::numeric_limits<COUNTER>::max)()};
212
214 {
215 static constexpr auto initial{"$1\0"sv};
216 initial.copy(std::data(m_buf), std::size(initial));
217 }
218
220
223 constexpr zview view() const & noexcept
224 {
225 return zview{std::data(m_buf), m_len};
226 }
227
229
234 std::string get() const { return std::string(std::data(m_buf), m_len); }
235
237 void next() &
238 {
239 if (m_current >= max_params)
241 "Too many parameters in one statement: limit is ", max_params, ".")};
242 PQXX_ASSUME(m_current > 0);
243 ++m_current;
244 if (m_current % 10 == 0)
245 {
246 // Carry the 1. Don't get too clever for this relatively rare
247 // case, just rewrite the entire number. Leave the $ in place
248 // though.
249 char *const data{std::data(m_buf)};
250 char *const end{string_traits<COUNTER>::into_buf(
251 data + 1, data + std::size(m_buf), m_current)};
252 // (Subtract because we don't include the trailing zero.)
253 m_len = check_cast<COUNTER>(end - data, "placeholders counter") - 1;
254 }
255 else
256 {
258 // Shortcut for the common case: just increment that last digit.
259 ++m_buf[m_len - 1];
260 }
261 }
262
264 COUNTER count() const noexcept { return m_current; }
265
266private:
268 COUNTER m_current = 1;
269
271 COUNTER m_len = 2;
272
274
281 std::array<char, std::numeric_limits<COUNTER>::digits10 + 3> m_buf;
282};
283} // namespace pqxx
284
285
288{
290template<typename IT>
291[[deprecated("Use the params class instead.")]] constexpr inline auto
292make_dynamic_params(IT begin, IT end)
293{
294 return pqxx::internal::dynamic_params(begin, end);
295}
296
297
299template<typename C>
300[[deprecated("Use the params class instead.")]] constexpr inline auto
301make_dynamic_params(C const &container)
302{
303 using IT = typename C::const_iterator;
305 return pqxx::internal::dynamic_params<IT>{container};
307}
308
309
311template<typename C, typename ACCESSOR>
312[[deprecated("Use the params class instead.")]] constexpr inline auto
313make_dynamic_params(C &container, ACCESSOR accessor)
314{
315 using IT = decltype(std::begin(container));
317 return pqxx::internal::dynamic_params<IT, ACCESSOR>{container, accessor};
319}
320} // namespace pqxx::prepare
321#endif
Definition statement_parameters.hxx:36
static constexpr unsigned int max_params
Maximum number of parameters we support.
Definition params.hxx:210
COUNTER count() const noexcept
Return the current placeholder number. The initial placeholder is 1.
Definition params.hxx:264
std::string get() const
Read the current placeholder text, as a std::string.
Definition params.hxx:234
placeholders()
Definition params.hxx:213
constexpr zview view() const &noexcept
Read an ephemeral version of the current placeholder text.
Definition params.hxx:223
void next() &
Move on to the next parameter.
Definition params.hxx:237
Marker-type wrapper: zero-terminated std::string_view.
Definition zview.hxx:38
Something is out of range, similar to std::out_of_range.
Definition except.hxx:326
#define PQXX_LIBEXPORT
Definition header-pre.hxx:157
#define PQXX_LIKELY
Definition header-pre.hxx:180
#define PQXX_ASSUME(condition)
Definition header-pre.hxx:189
std::string concat(TYPE... item)
Efficiently combine a bunch of items into one big string.
Definition concat.hxx:31
auto ssize(T const &c)
Transitional: std::ssize(), or custom implementation if not available.
Definition util.hxx:555
Definition params.hxx:288
constexpr auto make_dynamic_params(IT begin, IT end)
Definition params.hxx:292
The home of all libpqxx classes, functions, templates, etc.
Definition array.cxx:27
std::string to_string(T const &value)
Definition conversions.hxx:1249
constexpr void ignore_unused(T &&...) noexcept
Suppress compiler warning about an unused item.
Definition util.hxx:144
constexpr bool is_null(TYPE const &value) noexcept
Is value null?
Definition strconv.hxx:516
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
static char * into_buf(char *begin, char *end, TYPE const &value)
Write value's string representation into buffer at begin.