cursor.hxx 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. /** Definition of the iterator/container-style cursor classes.
  2. *
  3. * C++-style wrappers for SQL cursors
  4. *
  5. * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/cursor instead.
  6. *
  7. * Copyright (c) 2000-2019, 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 mistake,
  11. * or contact the author.
  12. */
  13. #ifndef PQXX_H_CURSOR
  14. #define PQXX_H_CURSOR
  15. #include "pqxx/compiler-public.hxx"
  16. #include "pqxx/compiler-internal-pre.hxx"
  17. #include <limits>
  18. #include <stdexcept>
  19. #include "pqxx/result.hxx"
  20. #include "pqxx/transaction_base.hxx"
  21. namespace pqxx
  22. {
  23. /// Common definitions for cursor types
  24. /** In C++ terms, fetches are always done in pre-increment or pre-decrement
  25. * fashion--i.e. the result does not include the row the cursor is on at the
  26. * beginning of the fetch, and the cursor ends up being positioned on the last
  27. * row in the result.
  28. *
  29. * There are singular positions akin to @c end() at both the beginning and the
  30. * end of the cursor's range of movement, although these fit in so naturally
  31. * with the semantics that one rarely notices them. The cursor begins at the
  32. * first of these, but any fetch in the forward direction will move the cursor
  33. * off this position and onto the first row before returning anything.
  34. */
  35. class PQXX_LIBEXPORT cursor_base
  36. {
  37. public:
  38. using size_type = result_size_type;
  39. using difference_type = result_difference_type;
  40. /// Cursor access-pattern policy
  41. /** Allowing a cursor to move forward only can result in better performance,
  42. * so use this access policy whenever possible.
  43. */
  44. enum accesspolicy
  45. {
  46. /// Cursor can move forward only
  47. forward_only,
  48. /// Cursor can move back and forth
  49. random_access
  50. };
  51. /// Cursor update policy
  52. /**
  53. * @warning Not all PostgreSQL versions support updatable cursors.
  54. */
  55. enum updatepolicy
  56. {
  57. /// Cursor can be used to read data but not to write
  58. read_only,
  59. /// Cursor can be used to update data as well as read it
  60. update
  61. };
  62. /// Cursor destruction policy
  63. /** The normal thing to do is to make a cursor object the owner of the SQL
  64. * cursor it represents. There may be cases, however, where a cursor needs to
  65. * persist beyond the end of the current transaction (and thus also beyond the
  66. * lifetime of the cursor object that created it!), where it can be "adopted"
  67. * into a new cursor object. See the basic_cursor documentation for an
  68. * explanation of cursor adoption.
  69. *
  70. * If a cursor is created with "loose" ownership policy, the object
  71. * representing the underlying SQL cursor will not take the latter with it
  72. * when its own lifetime ends, nor will its originating transaction.
  73. *
  74. * @warning Use this feature with care and moderation. Only one cursor object
  75. * should be responsible for any one underlying SQL cursor at any given time.
  76. *
  77. * @warning Don't "leak" cursors! As long as any "loose" cursor exists,
  78. * any attempts to deactivate or reactivate the connection, implicitly or
  79. * explicitly, are quietly ignored.
  80. */
  81. enum ownershippolicy
  82. {
  83. /// Destroy SQL cursor when cursor object is closed at end of transaction
  84. owned,
  85. /// Leave SQL cursor in existence after close of object and transaction
  86. loose
  87. };
  88. cursor_base() =delete;
  89. cursor_base(const cursor_base &) =delete;
  90. cursor_base &operator=(const cursor_base &) =delete;
  91. /**
  92. * @name Special movement distances.
  93. */
  94. //@{
  95. /// Special value: read until end.
  96. /** @return Maximum value for result::difference_type, so the cursor will
  97. * attempt to read the largest possible result set.
  98. */
  99. static difference_type all() noexcept; //[t81]
  100. /// Special value: read one row only.
  101. /** @return Unsurprisingly, 1.
  102. */
  103. static difference_type next() noexcept { return 1; } //[t81]
  104. /// Special value: read backwards, one row only.
  105. /** @return Unsurprisingly, -1.
  106. */
  107. static difference_type prior() noexcept { return -1; } //[t00]
  108. /// Special value: read backwards from current position back to origin.
  109. /** @return Minimum value for result::difference_type.
  110. */
  111. static difference_type backward_all() noexcept; //[t00]
  112. //@}
  113. /// Name of underlying SQL cursor
  114. /**
  115. * @returns Name of SQL cursor, which may differ from original given name.
  116. * @warning Don't use this to access the SQL cursor directly without going
  117. * through the provided wrapper classes!
  118. */
  119. const std::string &name() const noexcept { return m_name; } //[t81]
  120. protected:
  121. cursor_base(
  122. connection_base &,
  123. const std::string &Name,
  124. bool embellish_name=true);
  125. const std::string m_name;
  126. };
  127. } // namespace pqxx
  128. #include <pqxx/internal/sql_cursor.hxx>
  129. namespace pqxx
  130. {
  131. /// "Stateless cursor" class: easy API for retrieving parts of result sets
  132. /** This is a front-end for SQL cursors, but with a more C++-like API.
  133. *
  134. * Actually, stateless_cursor feels entirely different from SQL cursors. You
  135. * don't keep track of positions, fetches, and moves; you just say which rows
  136. * you want. See the retrieve() member function.
  137. */
  138. template<cursor_base::updatepolicy up, cursor_base::ownershippolicy op>
  139. class stateless_cursor
  140. {
  141. public:
  142. using size_type = result_size_type;
  143. using difference_type = result_difference_type;
  144. /// Create cursor.
  145. stateless_cursor(
  146. transaction_base &trans,
  147. const std::string &query,
  148. const std::string &cname,
  149. bool hold) :
  150. m_cur{trans, query, cname, cursor_base::random_access, up, op, hold}
  151. {
  152. }
  153. /// Adopt existing scrolling SQL cursor.
  154. stateless_cursor(
  155. transaction_base &trans,
  156. const std::string adopted_cursor) :
  157. m_cur{trans, adopted_cursor, op}
  158. {
  159. // Put cursor in known position
  160. m_cur.move(cursor_base::backward_all());
  161. }
  162. void close() noexcept { m_cur.close(); }
  163. /// Number of rows in cursor's result set
  164. /** @note This function is not const; it may need to scroll to find the size
  165. * of the result set.
  166. */
  167. size_type size() { return internal::obtain_stateless_cursor_size(m_cur); }
  168. /// Retrieve rows from begin_pos (inclusive) to end_pos (exclusive)
  169. /** Rows are numbered starting from 0 to size()-1.
  170. *
  171. * @param begin_pos First row to retrieve. May be one row beyond the end of
  172. * the result set, to avoid errors for empty result sets. Otherwise, must be
  173. * a valid row number in the result set.
  174. * @param end_pos Row up to which to fetch. Rows are returned ordered from
  175. * begin_pos to end_pos, i.e. in ascending order if begin_pos < end_pos but
  176. * in descending order if begin_pos > end_pos. The end_pos may be arbitrarily
  177. * inside or outside the result set; only existing rows are included in the
  178. * result.
  179. */
  180. result retrieve(difference_type begin_pos, difference_type end_pos)
  181. {
  182. return internal::stateless_cursor_retrieve(
  183. m_cur,
  184. result::difference_type(size()),
  185. begin_pos,
  186. end_pos);
  187. }
  188. const std::string &name() const noexcept { return m_cur.name(); }
  189. private:
  190. internal::sql_cursor m_cur;
  191. };
  192. class icursor_iterator;
  193. namespace internal
  194. {
  195. namespace gate
  196. {
  197. class icursor_iterator_icursorstream;
  198. class icursorstream_icursor_iterator;
  199. } // namespace internal::gate
  200. } // namespace internal
  201. /// Simple read-only cursor represented as a stream of results
  202. /** SQL cursors can be tricky, especially in C++ since the two languages seem to
  203. * have been designed on different planets. An SQL cursor has two singular
  204. * positions akin to @c end() on either side of the underlying result set.
  205. *
  206. * These cultural differences are hidden from view somewhat by libpqxx, which
  207. * tries to make SQL cursors behave more like familiar C++ entities such as
  208. * iterators, sequences, streams, and containers.
  209. *
  210. * Data is fetched from the cursor as a sequence of result objects. Each of
  211. * these will contain the number of rows defined as the stream's stride, except
  212. * of course the last block of data which may contain fewer rows.
  213. *
  214. * This class can create or adopt cursors that live outside any backend
  215. * transaction, which your backend version may not support.
  216. */
  217. class PQXX_LIBEXPORT icursorstream
  218. {
  219. public:
  220. using size_type = cursor_base::size_type;
  221. using difference_type = cursor_base::difference_type;
  222. /// Set up a read-only, forward-only cursor
  223. /** Roughly equivalent to a C++ Standard Library istream, this cursor type
  224. * supports only two operations: reading a block of rows while moving forward,
  225. * and moving forward without reading any data.
  226. *
  227. * @param context Transaction context that this cursor will be active in
  228. * @param query SQL query whose results this cursor shall iterate
  229. * @param basename Suggested name for the SQL cursor; a unique code will be
  230. * appended by the library to ensure its uniqueness
  231. * @param sstride Number of rows to fetch per read operation; must be a
  232. * positive number
  233. */
  234. icursorstream(
  235. transaction_base &context,
  236. const std::string &query,
  237. const std::string &basename,
  238. difference_type sstride=1); //[t81]
  239. /// Adopt existing SQL cursor. Use with care.
  240. /** Forms a cursor stream around an existing SQL cursor, as returned by e.g. a
  241. * server-side function. The SQL cursor will be cleaned up by the stream's
  242. * destructor as if it had been created by the stream; cleaning it up by hand
  243. * or adopting the same cursor twice is an error.
  244. *
  245. * Passing the name of the cursor as a string is not allowed, both to avoid
  246. * confusion with the other constructor and to discourage unnecessary use of
  247. * adopted cursors.
  248. *
  249. * @warning It is technically possible to adopt a "WITH HOLD" cursor, i.e. a
  250. * cursor that stays alive outside its creating transaction. However, any
  251. * cursor stream (including the underlying SQL cursor, naturally) must be
  252. * destroyed before its transaction context object is destroyed. Therefore
  253. * the only way to use SQL's WITH HOLD feature is to adopt the cursor, but
  254. * defer doing so until after entering the transaction context that will
  255. * eventually destroy it.
  256. *
  257. * @param context Transaction context that this cursor will be active in.
  258. * @param cname Result field containing the name of the SQL cursor to adopt.
  259. * @param sstride Number of rows to fetch per read operation; must be a
  260. * positive number.
  261. * @param op Ownership policy. Determines whether the cursor underlying this
  262. * stream will be destroyed when the stream is closed.
  263. */
  264. icursorstream(
  265. transaction_base &context,
  266. const field &cname,
  267. difference_type sstride=1,
  268. cursor_base::ownershippolicy op=cursor_base::owned); //[t84]
  269. operator bool() const noexcept { return not m_done; }
  270. /// Read new value into given result object; same as operator >>
  271. /** The result set may continue any number of rows from zero to the chosen
  272. * stride, inclusive. An empty result will only be returned if there are no
  273. * more rows to retrieve.
  274. * @return Reference to this very stream, to facilitate "chained" invocations
  275. * ("C.get(r1).get(r2);")
  276. */
  277. icursorstream &get(result &res) { res = fetchblock(); return *this; } //[t81]
  278. /// Read new value into given result object; same as get(result &)
  279. /** The result set may continue any number of rows from zero to the chosen
  280. * stride, inclusive. An empty result will only be returned if there are no
  281. * more rows to retrieve.
  282. * @return Reference to this very stream, to facilitate "chained" invocations
  283. * ("C >> r1 >> r2;")
  284. */
  285. icursorstream &operator>>(result &res) { return get(res); } //[t81]
  286. /// Move given number of rows forward (ignoring stride) without reading data
  287. /**
  288. * @return Reference to this very stream, to facilitate "chained" invocations
  289. * ("C.ignore(2).get(r).ignore(4);")
  290. */
  291. icursorstream &ignore(std::streamsize n=1); //[t81]
  292. /// Change stride, i.e. the number of rows to fetch per read operation
  293. /**
  294. * @param stride Must be a positive number
  295. */
  296. void set_stride(difference_type stride); //[t81]
  297. difference_type stride() const noexcept { return m_stride; } //[t81]
  298. private:
  299. result fetchblock();
  300. friend class internal::gate::icursorstream_icursor_iterator;
  301. size_type forward(size_type n=1);
  302. void insert_iterator(icursor_iterator *) noexcept;
  303. void remove_iterator(icursor_iterator *) const noexcept;
  304. void service_iterators(difference_type);
  305. internal::sql_cursor m_cur;
  306. difference_type m_stride;
  307. difference_type m_realpos, m_reqpos;
  308. mutable icursor_iterator *m_iterators;
  309. bool m_done;
  310. };
  311. /// Approximate istream_iterator for icursorstream
  312. /** Intended as an implementation of an input_iterator (as defined by the C++
  313. * Standard Library), this class supports only two basic operations: reading the
  314. * current element, and moving forward. In addition to the minimal guarantees
  315. * for istream_iterators, this class supports multiple successive reads of the
  316. * same position (the current result set is cached in the iterator) even after
  317. * copying and even after new data have been read from the stream. This appears
  318. * to be a requirement for input_iterators. Comparisons are also supported in
  319. * the general case.
  320. *
  321. * The iterator does not care about its own position, however. Moving an
  322. * iterator forward moves the underlying stream forward and reads the data from
  323. * the new stream position, regardless of the iterator's old position in the
  324. * stream.
  325. *
  326. * The stream's stride defines the granularity for all iterator movement or
  327. * access operations, i.e. "ici += 1" advances the stream by one stride's worth
  328. * of rows, and "*ici++" reads one stride's worth of rows from the stream.
  329. *
  330. * @warning Do not read from the underlying stream or its cursor, move its read
  331. * position, or change its stride, between the time the first icursor_iterator
  332. * on it is created and the time its last icursor_iterator is destroyed.
  333. *
  334. * @warning Manipulating these iterators within the context of a single cursor
  335. * stream is <em>not thread-safe</em>. Creating a new iterator, copying one, or
  336. * destroying one affects the stream as a whole.
  337. */
  338. class PQXX_LIBEXPORT icursor_iterator
  339. {
  340. public:
  341. using iterator_category = std::input_iterator_tag;
  342. using value_type = result;
  343. using pointer = const result *;
  344. using reference = const result &;
  345. using istream_type = icursorstream;
  346. using size_type = istream_type::size_type;
  347. using difference_type = istream_type::difference_type;
  348. icursor_iterator() noexcept; //[t84]
  349. explicit icursor_iterator(istream_type &) noexcept; //[t84]
  350. icursor_iterator(const icursor_iterator &) noexcept; //[t84]
  351. ~icursor_iterator() noexcept;
  352. const result &operator*() const { refresh(); return m_here; } //[t84]
  353. const result *operator->() const { refresh(); return &m_here; } //[t84]
  354. icursor_iterator &operator++(); //[t84]
  355. icursor_iterator operator++(int); //[t84]
  356. icursor_iterator &operator+=(difference_type); //[t84]
  357. icursor_iterator &operator=(const icursor_iterator &) noexcept; //[t84]
  358. bool operator==(const icursor_iterator &rhs) const; //[t84]
  359. bool operator!=(const icursor_iterator &rhs) const noexcept //[t84]
  360. { return not operator==(rhs); }
  361. bool operator<(const icursor_iterator &rhs) const; //[t84]
  362. bool operator>(const icursor_iterator &rhs) const //[t84]
  363. { return rhs < *this; }
  364. bool operator<=(const icursor_iterator &rhs) const //[t84]
  365. { return not (*this > rhs); }
  366. bool operator>=(const icursor_iterator &rhs) const //[t84]
  367. { return not (*this < rhs); }
  368. private:
  369. void refresh() const;
  370. friend class internal::gate::icursor_iterator_icursorstream;
  371. difference_type pos() const noexcept { return m_pos; }
  372. void fill(const result &);
  373. icursorstream *m_stream = nullptr;
  374. result m_here;
  375. difference_type m_pos;
  376. icursor_iterator *m_prev = nullptr, *m_next = nullptr;
  377. };
  378. } // namespace pqxx
  379. #include "pqxx/compiler-internal-post.hxx"
  380. #endif