libpqxx
The C++ client library for PostgreSQL
result.hxx
1 /* Definitions for the pqxx::result class and support classes.
2  *
3  * pqxx::result represents the set of result rows from a database query.
4  *
5  * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/result instead.
6  *
7  * Copyright (c) 2000-2025, Jeroen T. Vermeulen.
8  *
9  * See COPYING for copyright license. If you did not receive a file called
10  * COPYING with this source code, please notify the distributor of this
11  * mistake, or contact the author.
12  */
13 #ifndef PQXX_H_RESULT
14 #define PQXX_H_RESULT
15 
16 #if !defined(PQXX_HEADER_PRE)
17 # error "Include libpqxx headers as <pqxx/header>, not <pqxx/header.hxx>."
18 #endif
19 
20 #include <functional>
21 #include <ios>
22 #include <list>
23 #include <memory>
24 #include <stdexcept>
25 
26 #include "pqxx/except.hxx"
27 #include "pqxx/types.hxx"
28 #include "pqxx/util.hxx"
29 #include "pqxx/zview.hxx"
30 
31 #include "pqxx/internal/encodings.hxx"
32 
33 
34 namespace pqxx::internal
35 {
36 PQXX_LIBEXPORT void clear_result(pq::PGresult const *) noexcept;
37 } // namespace pqxx::internal
38 
39 
40 namespace pqxx::internal::gate
41 {
42 class result_connection;
43 class result_creation;
44 class result_pipeline;
45 class result_row;
46 class result_sql_cursor;
47 } // namespace pqxx::internal::gate
48 
49 
50 namespace pqxx::internal
51 {
52 // 9.0: Remove this, just use the notice handler in connection/result.
55 {
56  std::function<void(zview)> notice_handler;
57  std::list<errorhandler *> errorhandlers;
58 
59  notice_waiters() = default;
60  notice_waiters(notice_waiters const &) = delete;
61  notice_waiters(notice_waiters &&) = delete;
62  notice_waiters &operator=(notice_waiters const &) = delete;
63  notice_waiters &operator=(notice_waiters &&) = delete;
64 };
65 } // namespace pqxx::internal
66 
67 
68 namespace pqxx
69 {
71 
91 class PQXX_LIBEXPORT result
92 {
93 public:
94  using size_type = result_size_type;
95  using difference_type = result_difference_type;
96  using reference = row;
98  using pointer = const_iterator;
99  using iterator = const_iterator;
102 
103  result() noexcept :
104  m_data{}, m_query{}, m_encoding{internal::encoding_group::MONOBYTE}
105  {}
106 
107  result(result const &rhs) noexcept = default;
108  result(result &&rhs) noexcept = default;
109 
111 
114  result &operator=(result const &rhs) noexcept = default;
115 
117  result &operator=(result &&rhs) noexcept = default;
118 
127  [[nodiscard]] bool operator==(result const &) const noexcept;
130  [[nodiscard]] bool operator!=(result const &rhs) const noexcept
131  {
132  return not operator==(rhs);
133  }
135 
137 
143  template<typename... TYPE> auto iter() const;
144 
145  [[nodiscard]] const_reverse_iterator rbegin() const;
146  [[nodiscard]] const_reverse_iterator crbegin() const;
147  [[nodiscard]] const_reverse_iterator rend() const;
148  [[nodiscard]] const_reverse_iterator crend() const;
149 
150  [[nodiscard]] const_iterator begin() const noexcept;
151  [[nodiscard]] const_iterator cbegin() const noexcept;
152  [[nodiscard]] inline const_iterator end() const noexcept;
153  [[nodiscard]] inline const_iterator cend() const noexcept;
154 
155  [[nodiscard]] reference front() const noexcept;
156  [[nodiscard]] reference back() const noexcept;
157 
158  [[nodiscard]] PQXX_PURE size_type size() const noexcept;
159  [[nodiscard]] PQXX_PURE bool empty() const noexcept;
160  [[nodiscard]] size_type capacity() const noexcept { return size(); }
161 
163 
167  void swap(result &) noexcept;
168 
170 
174  [[nodiscard]] row operator[](size_type i) const noexcept;
175 
176 #if defined(PQXX_HAVE_MULTIDIM)
177  [[nodiscard]] field
178  operator[](size_type row_num, row_size_type col_num) const noexcept;
179 #endif // PQXX_HAVE_MULTIDIM
180 
182  row at(size_type) const;
183 
185  field at(size_type, row_size_type) const;
186 
188 
195  void clear() noexcept
196  {
197  m_data.reset();
198  m_query = nullptr;
199  }
200 
205  [[nodiscard]] PQXX_PURE row_size_type columns() const noexcept;
207 
209  [[nodiscard]] row_size_type column_number(zview name) const;
210 
212  [[nodiscard]] char const *column_name(row_size_type number) const &;
213 
215 
218  [[nodiscard]] int column_storage(row_size_type number) const;
219 
221 
231  [[nodiscard]] int column_type_modifier(row_size_type number) const noexcept;
232 
234  [[nodiscard]] oid column_type(row_size_type col_num) const;
235 
237  [[nodiscard]] oid column_type(zview col_name) const
238  {
239  return column_type(column_number(col_name));
240  }
241 
243  [[nodiscard]] oid column_table(row_size_type col_num) const;
244 
246  [[nodiscard]] oid column_table(zview col_name) const
247  {
248  return column_table(column_number(col_name));
249  }
250 
252  [[nodiscard]] row_size_type table_column(row_size_type col_num) const;
253 
255  [[nodiscard]] row_size_type table_column(zview col_name) const
256  {
257  return table_column(column_number(col_name));
258  }
260 
262  [[nodiscard]] PQXX_PURE std::string const &query() const & noexcept;
263 
265 
268  [[nodiscard]] PQXX_PURE oid inserted_oid() const;
269 
271 
274  [[nodiscard]] PQXX_PURE size_type affected_rows() const;
275 
276  // C++20: Concept like std::invocable, but without specifying param types.
278 
315  template<typename CALLABLE> inline void for_each(CALLABLE &&func) const;
316 
318 
321  result expect_rows(size_type n) const
322  {
323  auto const sz{size()};
324  if (sz != n)
325  {
326  // TODO: See whether result contains a generated statement.
327  if (not m_query or m_query->empty())
329  "Expected ", n, " row(s) from query, got ", sz, ".")};
330  else
332  "Expected ", n, " row(s) from query '", *m_query, "', got ", sz,
333  ".")};
334  }
335  return *this;
336  }
337 
339 
342  row one_row() const;
343 
345 
350  std::optional<row> opt_row() const;
351 
353  result no_rows() const
354  {
355  expect_rows(0);
356  return *this;
357  }
358 
360 
364  {
365  auto const actual{columns()};
366  if (actual != cols)
367  {
368  // TODO: See whether result contains a generated statement.
369  if (not m_query or m_query->empty())
371  "Expected ", cols, " column(s) from query, got ", actual, ".")};
372  else
374  "Expected ", cols, " column(s) from query '", *m_query, "', got ",
375  actual, ".")};
376  }
377  return *this;
378  }
379 
381 
384  field one_field() const;
385 
386 private:
387  using data_pointer = std::shared_ptr<internal::pq::PGresult const>;
388 
390  data_pointer m_data;
391 
393  PQXX_PURE std::shared_ptr<std::string const> query_ptr() const noexcept
394  {
395  return m_query;
396  }
397 
399  std::shared_ptr<std::string const> m_query;
400 
402 
406  std::shared_ptr<pqxx::internal::notice_waiters> m_notice_waiters;
407 
408  internal::encoding_group m_encoding;
409 
410  static std::string const s_empty_string;
411 
412  friend class pqxx::field;
413  PQXX_PURE char const *
414  get_value(size_type row, row_size_type col) const noexcept;
415  PQXX_PURE bool get_is_null(size_type row, row_size_type col) const noexcept;
416  PQXX_PURE
417  field_size_type get_length(size_type, row_size_type) const noexcept;
418 
419  friend class pqxx::internal::gate::result_creation;
420  result(
421  std::shared_ptr<internal::pq::PGresult> const &rhs,
422  std::shared_ptr<std::string> const &query,
423  std::shared_ptr<pqxx::internal::notice_waiters> const &waiters,
424  internal::encoding_group enc);
425 
426  PQXX_PRIVATE void check_status(std::string_view desc = ""sv) const;
427 
428  friend class pqxx::internal::gate::result_connection;
429  friend class pqxx::internal::gate::result_row;
430  bool operator!() const noexcept { return m_data.get() == nullptr; }
431  operator bool() const noexcept { return m_data.get() != nullptr; }
432 
433  [[noreturn]] PQXX_PRIVATE PQXX_COLD void
434  throw_sql_error(std::string const &Err, std::string const &Query) const;
435  PQXX_PRIVATE PQXX_PURE int errorposition() const;
436  PQXX_PRIVATE std::string status_error() const;
437 
439  PQXX_PURE char const *cmd_status() const noexcept;
440 };
441 } // namespace pqxx
442 #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
bool operator!=(result const &rhs) const noexcept
Compare two results for inequality.
Definition: result.hxx:130
Error in usage of libpqxx library, similar to std::logic_error.
Definition: except.hxx:248
row_size_type table_column(zview col_name) const
What column in its table did this column come from?
Definition: result.hxx:255
Internal items for libpqxx' own use. Do not use these yourself.
Definition: encodings.cxx:32
result expect_columns(row_size_type cols) const
Expect that result consists of exactly cols columns.
Definition: result.hxx:363
Reference to one row in a result.
Definition: row.hxx:46
oid column_table(zview col_name) const
What table did this column come from?
Definition: result.hxx:246
int row_size_type
Number of fields in a row of database data.
Definition: types.hxx:34
Result set containing data returned by a query or command.
Definition: result.hxx:91
Various callbacks waiting for a notice to come in.
Definition: result.hxx:54
int result_size_type
Number of rows in a result set.
Definition: types.hxx:28
PQXX_LIBEXPORT void clear_result(pq::PGresult const *) noexcept
C++ wrapper for libpq's PQclear.
Definition: result.cxx:42
int result_difference_type
Difference between result sizes.
Definition: types.hxx:31
Query returned an unexpected number of rows.
Definition: except.hxx:342
The home of all libpqxx classes, functions, templates, etc.
Definition: array.cxx:26
Reference to a field in a result set.
Definition: field.hxx:34
unsigned int oid
PostgreSQL database row identifier.
Definition: libpq-forward.hxx:33
Iterator for rows in a result. Use as result::const_iterator.
Definition: result_iterator.hxx:32
std::size_t field_size_type
Number of bytes in a field of database data.
Definition: types.hxx:40
Definition: result-sql_cursor.hxx:5
result no_rows() const
Expect that result contains no rows. Return result for convenience.
Definition: result.hxx:353
Reverse iterator for result. Use as result::const_reverse_iterator.
Definition: result_iterator.hxx:194
void clear() noexcept
Let go of the result's data.
Definition: result.hxx:195
Definition: result-pipeline.hxx:5