ZeroTierOne/ext/libpqxx-7.7.3/install/ubuntu22.04/include/pqxx/result.hxx
2022-06-24 10:12:36 -07:00

336 lines
11 KiB
C++

/* Definitions for the pqxx::result class and support classes.
*
* pqxx::result represents the set of result rows from a database query.
*
* DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/result instead.
*
* Copyright (c) 2000-2022, Jeroen T. Vermeulen.
*
* See COPYING for copyright license. If you did not receive a file called
* COPYING with this source code, please notify the distributor of this
* mistake, or contact the author.
*/
#ifndef PQXX_H_RESULT
#define PQXX_H_RESULT
#if !defined(PQXX_HEADER_PRE)
# error "Include libpqxx headers as <pqxx/header>, not <pqxx/header.hxx>."
#endif
#include <functional>
#include <ios>
#include <memory>
#include <stdexcept>
#include "pqxx/except.hxx"
#include "pqxx/types.hxx"
#include "pqxx/util.hxx"
#include "pqxx/zview.hxx"
#include "pqxx/internal/encodings.hxx"
namespace pqxx::internal
{
// TODO: Make noexcept (but breaks ABI).
PQXX_LIBEXPORT void clear_result(pq::PGresult const *);
} // namespace pqxx::internal
namespace pqxx::internal::gate
{
class result_connection;
class result_creation;
class result_pipeline;
class result_row;
class result_sql_cursor;
} // namespace pqxx::internal::gate
namespace pqxx
{
/// Result set containing data returned by a query or command.
/** This behaves as a container (as defined by the C++ standard library) and
* provides random access const iterators to iterate over its rows. You can
* also access a row by indexing a `result R` by the row's zero-based
* number:
*
*
* for (result::size_type i=0; i < std::size(R); ++i) Process(R[i]);
*
*
* Result sets in libpqxx are lightweight, reference-counted wrapper objects
* which are relatively small and cheap to copy. Think of a result object as
* a "smart pointer" to an underlying result set.
*
* @warning The result set that a result object points to is not thread-safe.
* If you copy a result object, it still refers to the same underlying result
* set. So never copy, destroy, query, or otherwise access a result while
* another thread may be copying, destroying, querying, or otherwise accessing
* the same result set--even if it is doing so through a different result
* object!
*/
class PQXX_LIBEXPORT result
{
public:
using size_type = result_size_type;
using difference_type = result_difference_type;
using reference = row;
using const_iterator = const_result_iterator;
using pointer = const_iterator;
using iterator = const_iterator;
using const_reverse_iterator = const_reverse_result_iterator;
using reverse_iterator = const_reverse_iterator;
result() noexcept :
m_data{make_data_pointer()},
m_query{},
m_encoding{internal::encoding_group::MONOBYTE}
{}
result(result const &rhs) noexcept = default;
result(result &&rhs) noexcept = default;
/// Assign one result to another.
/** Copying results is cheap: it copies only smart pointers, but the actual
* data stays in the same place.
*/
result &operator=(result const &rhs) noexcept = default;
/// Assign one result to another, invaliding the old one.
result &operator=(result &&rhs) noexcept = default;
/**
* @name Comparisons
*
* You can compare results for equality. Beware: this is a very strict,
* dumb comparison. The smallest difference between two results (such as a
* string "Foo" versus a string "foo") will make them unequal.
*/
//@{
/// Compare two results for equality.
[[nodiscard]] bool operator==(result const &) const noexcept;
/// Compare two results for inequality.
[[nodiscard]] bool operator!=(result const &rhs) const noexcept
{
return not operator==(rhs);
}
//@}
/// Iterate rows, reading them directly into a tuple of "TYPE...".
/** Converts the fields to values of the given respective types.
*
* Use this only with a ranged "for" loop. The iteration produces
* std::tuple<TYPE...> which you can "unpack" to a series of `auto`
* variables.
*/
template<typename... TYPE> auto iter() const;
[[nodiscard]] const_reverse_iterator rbegin() const;
[[nodiscard]] const_reverse_iterator crbegin() const;
[[nodiscard]] const_reverse_iterator rend() const;
[[nodiscard]] const_reverse_iterator crend() const;
[[nodiscard]] const_iterator begin() const noexcept;
[[nodiscard]] const_iterator cbegin() const noexcept;
[[nodiscard]] inline const_iterator end() const noexcept;
[[nodiscard]] inline const_iterator cend() const noexcept;
[[nodiscard]] reference front() const noexcept;
[[nodiscard]] reference back() const noexcept;
[[nodiscard]] PQXX_PURE size_type size() const noexcept;
[[nodiscard]] PQXX_PURE bool empty() const noexcept;
[[nodiscard]] size_type capacity() const noexcept { return size(); }
/// Exchange two `result` values in an exception-safe manner.
/** If the swap fails, the two values will be exactly as they were before.
*
* The swap is not necessarily thread-safe.
*/
void swap(result &) noexcept;
/// Index a row by number.
/** This returns a @ref row object. Generally you should not keep the row
* around as a variable, but if you do, make sure that your variable is a
* `row`, not a `row&`.
*/
[[nodiscard]] row operator[](size_type i) const noexcept;
#if defined(PQXX_HAVE_MULTIDIMENSIONAL_SUBSCRIPT)
// TODO: If C++23 will let us, also accept string for the column.
[[nodiscard]] field
operator[](size_type row_num, row_size_type col_num) const noexcept;
#endif
/// Index a row by number, but check that the row number is valid.
row at(size_type) const;
/// Index a field by row number and column number.
field at(size_type, row_size_type) const;
/// Let go of the result's data.
/** Use this if you need to deallocate the result data earlier than you can
* destroy the `result` object itself.
*
* Multiple `result` objects can refer to the same set of underlying data.
* The underlying data will be deallocated once all `result` objects that
* refer to it are cleared or destroyed.
*/
void clear() noexcept
{
m_data.reset();
m_query = nullptr;
}
/**
* @name Column information
*/
//@{
/// Number of columns in result.
[[nodiscard]] PQXX_PURE row_size_type columns() const noexcept;
/// Number of given column (throws exception if it doesn't exist).
[[nodiscard]] row_size_type column_number(zview name) const;
/// Name of column with this number (throws exception if it doesn't exist)
[[nodiscard]] char const *column_name(row_size_type number) const &;
/// Return column's type, as an OID from the system catalogue.
[[nodiscard]] oid column_type(row_size_type col_num) const;
/// Return column's type, as an OID from the system catalogue.
[[nodiscard]] oid column_type(zview col_name) const
{
return column_type(column_number(col_name));
}
/// What table did this column come from?
[[nodiscard]] oid column_table(row_size_type col_num) const;
/// What table did this column come from?
[[nodiscard]] oid column_table(zview col_name) const
{
return column_table(column_number(col_name));
}
/// What column in its table did this column come from?
[[nodiscard]] row_size_type table_column(row_size_type col_num) const;
/// What column in its table did this column come from?
[[nodiscard]] row_size_type table_column(zview col_name) const
{
return table_column(column_number(col_name));
}
//@}
/// Query that produced this result, if available (empty string otherwise)
[[nodiscard]] PQXX_PURE std::string const &query() const &noexcept;
/// If command was an `INSERT` of 1 row, return oid of the inserted row.
/** @return Identifier of inserted row if exactly one row was inserted, or
* @ref oid_none otherwise.
*/
[[nodiscard]] PQXX_PURE oid inserted_oid() const;
/// If command was `INSERT`, `UPDATE`, or `DELETE`: number of affected rows.
/** @return Number of affected rows if last command was `INSERT`, `UPDATE`,
* or `DELETE`; zero for all other commands.
*/
[[nodiscard]] PQXX_PURE size_type affected_rows() const;
// C++20: Concept like std::invocable, but without specifying param types.
/// Run `func` on each row, passing the row's fields as parameters.
/** Goes through the rows from first to last. You provide a callable `func`.
*
* For each row in the `result`, `for_each` will call `func`. It converts
* the row's fields to the types of `func`'s parameters, and pass them to
* `func`.
*
* (Therefore `func` must have a _single_ signature. It can't be a generic
* lambda, or an object of a class with multiple overloaded function call
* operators. Otherwise, `for_each` will have no way to detect a parameter
* list without ambiguity.)
*
* If any of your parameter types is `std::string_view`, it refers to the
* underlying storage of this `result`.
*
* If any of your parameter types is a reference type, its argument will
* refer to a temporary value which only lives for the duration of that
* single invocation to `func`. If the reference is an lvalue reference, it
* must be `const`.
*
* For example, this queries employee names and salaries from the database
* and prints how much each would like to earn instead:
* ```cxx
* tx.exec("SELECT name, salary FROM employee").for_each(
* [](std::string_view name, float salary){
* std::cout << name << " would like " << salary * 2 << ".\n";
* })
* ```
*
* If `func` throws an exception, processing stops at that point and
* propagates the exception.
*
* @throws usage_error if `func`'s number of parameters does not match the
* number of columns in this result.
*/
template<typename CALLABLE> inline void for_each(CALLABLE &&func) const;
private:
using data_pointer = std::shared_ptr<internal::pq::PGresult const>;
/// Underlying libpq result set.
data_pointer m_data;
/// Factory for data_pointer.
static data_pointer
make_data_pointer(internal::pq::PGresult const *res = nullptr) noexcept
{
return {res, internal::clear_result};
}
friend class pqxx::internal::gate::result_pipeline;
PQXX_PURE std::shared_ptr<std::string const> query_ptr() const noexcept
{
return m_query;
}
/// Query string.
std::shared_ptr<std::string const> m_query;
internal::encoding_group m_encoding;
static std::string const s_empty_string;
friend class pqxx::field;
// TODO: noexcept. Breaks ABI.
PQXX_PURE char const *get_value(size_type row, row_size_type col) const;
// TODO: noexcept. Breaks ABI.
PQXX_PURE bool get_is_null(size_type row, row_size_type col) const;
PQXX_PURE
field_size_type get_length(size_type, row_size_type) const noexcept;
friend class pqxx::internal::gate::result_creation;
result(
internal::pq::PGresult *rhs, std::shared_ptr<std::string> query,
internal::encoding_group enc);
PQXX_PRIVATE void check_status(std::string_view desc = ""sv) const;
friend class pqxx::internal::gate::result_connection;
friend class pqxx::internal::gate::result_row;
bool operator!() const noexcept { return m_data.get() == nullptr; }
operator bool() const noexcept { return m_data.get() != nullptr; }
[[noreturn]] PQXX_PRIVATE void
throw_sql_error(std::string const &Err, std::string const &Query) const;
PQXX_PRIVATE PQXX_PURE int errorposition() const;
PQXX_PRIVATE std::string status_error() const;
friend class pqxx::internal::gate::result_sql_cursor;
PQXX_PURE char const *cmd_status() const noexcept;
};
} // namespace pqxx
#endif