-
Notifications
You must be signed in to change notification settings - Fork 228
/
result.hxx
281 lines (227 loc) · 8.75 KB
/
result.hxx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
/** 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) 2001-2017, 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
#include "pqxx/compiler-public.hxx"
#include "pqxx/compiler-internal-pre.hxx"
#include <ios>
#include <stdexcept>
#include "pqxx/except"
#include "pqxx/field"
#include "pqxx/util"
/* Methods tested in eg. self-test program test001 are marked with "//[t1]"
*/
// TODO: Support SQL arrays
namespace pqxx
{
namespace internal
{
PQXX_LIBEXPORT void clear_result(const pq::PGresult *);
namespace gate
{
class result_connection;
class result_creation;
class result_row;
class result_sql_cursor;
} // namespace internal::gate
} // namespace internal
/// 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. A row
* can also be accessed by indexing a result R by the row's zero-based
* number:
*
* @code
* for (result::size_type i=0; i < R.size(); ++i) Process(R[i]);
* @endcode
*
* 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() {} //[t3]
result(const result &rhs) noexcept : //[t1]
m_data(rhs.m_data), m_query(rhs.m_query) {}
result &operator=(const result &rhs) noexcept //[t10]
{
m_data = rhs.m_data;
m_query = rhs.m_query;
return *this;
}
/**
* @name Comparisons
*/
//@{
bool operator==(const result &) const noexcept; //[t70]
bool operator!=(const result &rhs) const noexcept //[t70]
{ return !operator==(rhs); }
//@}
const_reverse_iterator rbegin() const; //[t75]
const_reverse_iterator crbegin() const;
const_reverse_iterator rend() const; //[t75]
const_reverse_iterator crend() const;
const_iterator begin() const noexcept; //[t1]
const_iterator cbegin() const noexcept;
inline const_iterator end() const noexcept; //[t1]
inline const_iterator cend() const noexcept;
reference front() const noexcept; //[t74]
reference back() const noexcept; //[t75]
PQXX_PURE size_type size() const noexcept; //[t2]
PQXX_PURE bool empty() const noexcept; //[t11]
size_type capacity() const noexcept { return size(); } //[t20]
void swap(result &) noexcept; //[t77]
const row operator[](size_type i) const noexcept; //[t2]
const row at(size_type) const; //[t10]
void clear() noexcept { m_data.reset(); m_query.erase(); } //[t20]
/**
* @name Column information
*/
//@{
/// Number of columns in result.
PQXX_PURE row_size_type columns() const noexcept; //[t11]
/// Number of given column (throws exception if it doesn't exist).
row_size_type column_number(const char ColName[]) const; //[t11]
/// Number of given column (throws exception if it doesn't exist).
row_size_type column_number(const std::string &Name) const //[t11]
{return column_number(Name.c_str());}
/// Name of column with this number (throws exception if it doesn't exist)
const char *column_name(row_size_type Number) const; //[t11]
/// Type of given column
oid column_type(row_size_type ColNum) const; //[t7]
/// Type of given column
oid column_type(int ColNum) const //[t7]
{ return column_type(row_size_type(ColNum)); }
/// Type of given column
oid column_type(const std::string &ColName) const //[t7]
{ return column_type(column_number(ColName)); }
/// Type of given column
oid column_type(const char ColName[]) const //[t7]
{ return column_type(column_number(ColName)); }
/// What table did this column come from?
oid column_table(row_size_type ColNum) const; //[t2]
/// What table did this column come from?
oid column_table(int ColNum) const //[t2]
{ return column_table(row_size_type(ColNum)); }
/// What table did this column come from?
oid column_table(const std::string &ColName) const //[t2]
{ return column_table(column_number(ColName)); }
/// What column in its table did this column come from?
row_size_type table_column(row_size_type ColNum) const; //[t93]
/// What column in its table did this column come from?
row_size_type table_column(int ColNum) const //[t93]
{ return table_column(row_size_type(ColNum)); }
/// What column in its table did this column come from?
row_size_type table_column(const std::string &ColName) const //[t93]
{ return table_column(column_number(ColName)); }
//@}
/// Query that produced this result, if available (empty string otherwise)
PQXX_PURE const std::string &query() const noexcept; //[t70]
/// If command was @c INSERT of 1 row, return oid of inserted row
/** @return Identifier of inserted row if exactly one row was inserted, or
* oid_none otherwise.
*/
PQXX_PURE oid inserted_oid() const; //[t13]
/// If command was @c INSERT, @c UPDATE, or @c DELETE: number of affected rows
/** @return Number of affected rows if last command was @c INSERT, @c UPDATE,
* or @c DELETE; zero for all other commands.
*/
PQXX_PURE size_type affected_rows() const; //[t7]
private:
using data_pointer = std::shared_ptr<const internal::pq::PGresult>;
/// Underlying libpq result set.
data_pointer m_data;
/// Factory for data_pointer.
static data_pointer make_data_pointer(
const internal::pq::PGresult *res=nullptr)
{ return data_pointer(res, internal::clear_result); }
/// Query string.
std::string m_query;
friend class pqxx::field;
PQXX_PURE const char *GetValue(size_type Row, row_size_type Col) const;
PQXX_PURE bool GetIsNull(size_type Row, row_size_type Col) const;
PQXX_PURE field_size_type GetLength(
size_type,
row_size_type) const noexcept;
friend class pqxx::internal::gate::result_creation;
result(internal::pq::PGresult *rhs, const std::string &Query);
PQXX_PRIVATE void CheckStatus() const;
friend class pqxx::internal::gate::result_connection;
friend class pqxx::internal::gate::result_row;
bool operator!() const noexcept { return !m_data.get(); }
operator bool() const noexcept { return m_data.get(); }
[[noreturn]] PQXX_PRIVATE void ThrowSQLError(
const std::string &Err,
const std::string &Query) const;
PQXX_PRIVATE PQXX_PURE int errorposition() const noexcept;
PQXX_PRIVATE std::string StatusError() const;
friend class pqxx::internal::gate::result_sql_cursor;
PQXX_PURE const char *CmdStatus() const noexcept;
};
/// Write a result field to any type of stream
/** This can be convenient when writing a field to an output stream. More
* importantly, it lets you write a field to e.g. a @c stringstream which you
* can then use to read, format and convert the field in ways that to() does not
* support.
*
* Example: parse a field into a variable of the nonstandard
* "<tt>long long</tt>" type.
*
* @code
* extern result R;
* long long L;
* stringstream S;
*
* // Write field's string into S
* S << R[0][0];
*
* // Parse contents of S into L
* S >> L;
* @endcode
*/
template<typename CHAR>
inline std::basic_ostream<CHAR> &operator<<(
std::basic_ostream<CHAR> &S, const pqxx::field &F) //[t46]
{
S.write(F.c_str(), std::streamsize(F.size()));
return S;
}
/// Convert a field's string contents to another type
template<typename T>
inline void from_string(const field &F, T &Obj) //[t46]
{ from_string(F.c_str(), Obj, F.size()); }
/// Convert a field to a string
template<>
inline std::string to_string(const field &Obj) //[t74]
{ return std::string(Obj.c_str(), Obj.size()); }
} // namespace pqxx
#include "pqxx/result_iterator.hxx"
#include "pqxx/compiler-internal-post.hxx"
#endif