blob.hxx 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. /* Binary Large Objects interface.
  2. *
  3. * Read or write large objects, stored in their own storage on the server.
  4. *
  5. * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/largeobject instead.
  6. *
  7. * Copyright (c) 2000-2022, 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_BLOB
  14. #define PQXX_H_BLOB
  15. #if !defined(PQXX_HEADER_PRE)
  16. # error "Include libpqxx headers as <pqxx/header>, not <pqxx/header.hxx>."
  17. #endif
  18. #include <cstdint>
  19. #if defined(PQXX_HAVE_PATH)
  20. # include <filesystem>
  21. #endif
  22. #if defined(PQXX_HAVE_RANGES) && __has_include(<ranges>)
  23. # include <ranges>
  24. #endif
  25. #if defined(PQXX_HAVE_SPAN) && __has_include(<span>)
  26. # include <span>
  27. #endif
  28. #include "pqxx/dbtransaction.hxx"
  29. namespace pqxx
  30. {
  31. /** Binary large object.
  32. *
  33. * This is how you store data that may be too large for the `BYTEA` type.
  34. * Access operations are similar to those for a file: you can read, write,
  35. * query or set the current reading/writing position, and so on.
  36. *
  37. * These large objects live in their own storage on the server, indexed by an
  38. * integer object identifier ("oid").
  39. *
  40. * Two `blob` objects may refer to the same actual large object in the
  41. * database at the same time. Each will have its own reading/writing position,
  42. * but writes to the one will of course affect what the other sees.
  43. */
  44. class PQXX_LIBEXPORT blob
  45. {
  46. public:
  47. /// Create a new, empty large object.
  48. /** You may optionally specify an oid for the new blob. If you do, then
  49. * the new object will have that oid -- or creation will fail if there
  50. * already is an object with that oid.
  51. */
  52. [[nodiscard]] static oid create(dbtransaction &, oid = 0);
  53. /// Delete a large object, or fail if it does not exist.
  54. static void remove(dbtransaction &, oid);
  55. /// Open blob for reading. Any attempt to write to it will fail.
  56. [[nodiscard]] static blob open_r(dbtransaction &, oid);
  57. // Open blob for writing. Any attempt to read from it will fail.
  58. [[nodiscard]] static blob open_w(dbtransaction &, oid);
  59. // Open blob for reading and/or writing.
  60. [[nodiscard]] static blob open_rw(dbtransaction &, oid);
  61. /// You can default-construct a blob, but it won't do anything useful.
  62. /** Most operations on a default-constructed blob will throw @ref
  63. * usage_error.
  64. */
  65. blob() = default;
  66. /// You can move a blob, but not copy it. The original becomes unusable.
  67. blob(blob &&);
  68. /// You can move a blob, but not copy it. The original becomes unusable.
  69. blob &operator=(blob &&);
  70. blob(blob const &) = delete;
  71. blob &operator=(blob const &) = delete;
  72. ~blob();
  73. /// Maximum number of bytes that can be read or written at a time.
  74. /** The underlying protocol only supports reads and writes up to 2 GB
  75. * exclusive.
  76. *
  77. * If you need to read or write more data to or from a binary large object,
  78. * you'll have to break it up into chunks.
  79. */
  80. static constexpr std::size_t chunk_limit = 0x7fffffff;
  81. /// Read up to `size` bytes of the object into `buf`.
  82. /** Uses a buffer that you provide, resizing it as needed. If it suits you,
  83. * this lets you allocate the buffer once and then re-use it multiple times.
  84. *
  85. * Resizes `buf` as needed.
  86. *
  87. * @warning The underlying protocol only supports reads up to 2GB at a time.
  88. * If you need to read more, try making repeated calls to @ref append_to_buf.
  89. */
  90. std::size_t read(std::basic_string<std::byte> &buf, std::size_t size);
  91. #if defined(PQXX_HAVE_SPAN)
  92. /// Read up to `std::size(buf)` bytes from the object.
  93. /** Retrieves bytes from the blob, at the current position, until `buf` is
  94. * full or there are no more bytes to read, whichever comes first.
  95. *
  96. * Returns the filled portion of `buf`. This may be empty.
  97. */
  98. template<std::size_t extent = std::dynamic_extent>
  99. std::span<std::byte> read(std::span<std::byte, extent> buf)
  100. {
  101. return buf.subspan(0, raw_read(std::data(buf), std::size(buf)));
  102. }
  103. #endif // PQXX_HAVE_SPAN
  104. #if defined(PQXX_HAVE_CONCEPTS) && defined(PQXX_HAVE_SPAN)
  105. /// Read up to `std::size(buf)` bytes from the object.
  106. /** Retrieves bytes from the blob, at the current position, until `buf` is
  107. * full or there are no more bytes to read, whichever comes first.
  108. *
  109. * Returns the filled portion of `buf`. This may be empty.
  110. */
  111. template<binary DATA> std::span<std::byte> read(DATA &buf)
  112. {
  113. return {std::data(buf), raw_read(std::data(buf), std::size(buf))};
  114. }
  115. #else // PQXX_HAVE_CONCEPTS && PQXX_HAVE_SPAN
  116. /// Read up to `std::size(buf)` bytes from the object.
  117. /** @deprecated As libpqxx moves to C++20 as its baseline language version,
  118. * this will take and return `std::span<std::byte>`.
  119. *
  120. * Retrieves bytes from the blob, at the current position, until `buf` is
  121. * full (i.e. its current size is reached), or there are no more bytes to
  122. * read, whichever comes first.
  123. *
  124. * This function will not change either the size or the capacity of `buf`,
  125. * only its contents.
  126. *
  127. * Returns the filled portion of `buf`. This may be empty.
  128. */
  129. template<typename ALLOC>
  130. std::basic_string_view<std::byte> read(std::vector<std::byte, ALLOC> &buf)
  131. {
  132. return {std::data(buf), raw_read(std::data(buf), std::size(buf))};
  133. }
  134. #endif // PQXX_HAVE_CONCEPTS && PQXX_HAVE_SPAN
  135. #if defined(PQXX_HAVE_CONCEPTS)
  136. /// Write `data` to large object, at the current position.
  137. /** If the writing position is at the end of the object, this will append
  138. * `data` to the object's contents and move the writing position so that
  139. * it's still at the end.
  140. *
  141. * If the writing position was not at the end, writing will overwrite the
  142. * prior data, but it will not remove data that follows the part where you
  143. * wrote your new data.
  144. *
  145. * @warning This is a big difference from writing to a file. You can
  146. * overwrite some data in a large object, but this does not truncate the
  147. * data that was already there. For example, if the object contained binary
  148. * data "abc", and you write "12" at the starting position, the object will
  149. * contain "12c".
  150. *
  151. * @warning The underlying protocol only supports writes up to 2 GB at a
  152. * time. If you need to write more, try making repeated calls to
  153. * @ref append_from_buf.
  154. */
  155. template<binary DATA> void write(DATA const &data)
  156. {
  157. raw_write(std::data(data), std::size(data));
  158. }
  159. #else
  160. /// Write `data` large object, at the current position.
  161. /** If the writing position is at the end of the object, this will append
  162. * `data` to the object's contents and move the writing position so that
  163. * it's still at the end.
  164. *
  165. * If the writing position was not at the end, writing will overwrite the
  166. * prior data, but it will not remove data that follows the part where you
  167. * wrote your new data.
  168. *
  169. * @warning This is a big difference from writing to a file. You can
  170. * overwrite some data in a large object, but this does not truncate the
  171. * data that was already there. For example, if the object contained binary
  172. * data "abc", and you write "12" at the starting position, the object will
  173. * contain "12c".
  174. *
  175. * @warning The underlying protocol only supports writes up to 2 GB at a
  176. * time. If you need to write more, try making repeated calls to
  177. * @ref append_from_buf.
  178. */
  179. template<typename DATA> void write(DATA const &data)
  180. {
  181. raw_write(std::data(data), std::size(data));
  182. }
  183. #endif
  184. /// Resize large object to `size` bytes.
  185. /** If the blob is more than `size` bytes long, this removes the end so as
  186. * to make the blob the desired length.
  187. *
  188. * If the blob is less than `size` bytes long, it adds enough zero bytes to
  189. * make it the desired length.
  190. */
  191. void resize(std::int64_t size);
  192. /// Return the current reading/writing position in the large object.
  193. [[nodiscard]] std::int64_t tell() const;
  194. /// Set the current reading/writing position to an absolute offset.
  195. /** Returns the new file offset. */
  196. std::int64_t seek_abs(std::int64_t offset = 0);
  197. /// Move the current reading/writing position forwards by an offset.
  198. /** To move backwards, pass a negative offset.
  199. *
  200. * Returns the new file offset.
  201. */
  202. std::int64_t seek_rel(std::int64_t offset = 0);
  203. /// Set the current position to an offset relative to the end of the blob.
  204. /** You'll probably want an offset of zero or less.
  205. *
  206. * Returns the new file offset.
  207. */
  208. std::int64_t seek_end(std::int64_t offset = 0);
  209. /// Create a binary large object containing given `data`.
  210. /** You may optionally specify an oid for the new object. If you do, and an
  211. * object with that oid already exists, creation will fail.
  212. */
  213. static oid from_buf(
  214. dbtransaction &tx, std::basic_string_view<std::byte> data, oid id = 0);
  215. /// Append `data` to binary large object.
  216. /** The underlying protocol only supports appending blocks up to 2 GB.
  217. */
  218. static void append_from_buf(
  219. dbtransaction &tx, std::basic_string_view<std::byte> data, oid id);
  220. /// Read client-side file and store it server-side as a binary large object.
  221. [[nodiscard]] static oid from_file(dbtransaction &, char const path[]);
  222. #if defined(PQXX_HAVE_PATH) && !defined(_WIN32)
  223. /// Read client-side file and store it server-side as a binary large object.
  224. /** This overload is not available on Windows, where `std::filesystem::path`
  225. * converts to a `wchar_t` string rather than a `char` string.
  226. */
  227. [[nodiscard]] static oid
  228. from_file(dbtransaction &tx, std::filesystem::path const &path)
  229. {
  230. return from_file(tx, path.c_str());
  231. }
  232. #endif
  233. /// Read client-side file and store it server-side as a binary large object.
  234. /** In this version, you specify the binary large object's oid. If that oid
  235. * is already in use, the operation will fail.
  236. */
  237. static oid from_file(dbtransaction &, char const path[], oid);
  238. #if defined(PQXX_HAVE_PATH) && !defined(_WIN32)
  239. /// Read client-side file and store it server-side as a binary large object.
  240. /** In this version, you specify the binary large object's oid. If that oid
  241. * is already in use, the operation will fail.
  242. *
  243. * This overload is not available on Windows, where `std::filesystem::path`
  244. * converts to a `wchar_t` string rather than a `char` string.
  245. */
  246. static oid
  247. from_file(dbtransaction &tx, std::filesystem::path const &path, oid id)
  248. {
  249. return from_file(tx, path.c_str(), id);
  250. }
  251. #endif
  252. /// Convenience function: Read up to `max_size` bytes from blob with `id`.
  253. /** You could easily do this yourself using the @ref open_r and @ref read
  254. * functions, but it can save you a bit of code to do it this way.
  255. */
  256. static void to_buf(
  257. dbtransaction &, oid, std::basic_string<std::byte> &,
  258. std::size_t max_size);
  259. /// Read part of the binary large object with `id`, and append it to `buf`.
  260. /** Use this to break up a large read from one binary large object into one
  261. * massive buffer. Just keep calling this function until it returns zero.
  262. *
  263. * The `offset` is how far into the large object your desired chunk is, and
  264. * `append_max` says how much to try and read in one go.
  265. */
  266. static std::size_t append_to_buf(
  267. dbtransaction &tx, oid id, std::int64_t offset,
  268. std::basic_string<std::byte> &buf, std::size_t append_max);
  269. /// Write a binary large object's contents to a client-side file.
  270. static void to_file(dbtransaction &, oid, char const path[]);
  271. #if defined(PQXX_HAVE_PATH) && !defined(_WIN32)
  272. /// Write a binary large object's contents to a client-side file.
  273. /** This overload is not available on Windows, where `std::filesystem::path`
  274. * converts to a `wchar_t` string rather than a `char` string.
  275. */
  276. static void
  277. to_file(dbtransaction &tx, oid id, std::filesystem::path const &path)
  278. {
  279. to_file(tx, id, path.c_str());
  280. }
  281. #endif
  282. /// Close this blob.
  283. /** This does not delete the blob from the database; it only terminates your
  284. * local object for accessing the blob.
  285. *
  286. * Resets the blob to a useless state similar to one that was
  287. * default-constructed.
  288. *
  289. * The destructor will do this for you automatically. Still, there is a
  290. * reason to `close()` objects explicitly where possible: if an error should
  291. * occur while closing, `close()` can throw an exception. A destructor
  292. * cannot.
  293. */
  294. void close();
  295. private:
  296. PQXX_PRIVATE blob(connection &conn, int fd) noexcept :
  297. m_conn{&conn}, m_fd{fd}
  298. {}
  299. static PQXX_PRIVATE blob open_internal(dbtransaction &, oid, int);
  300. static PQXX_PRIVATE pqxx::internal::pq::PGconn *
  301. raw_conn(pqxx::connection *) noexcept;
  302. static PQXX_PRIVATE pqxx::internal::pq::PGconn *
  303. raw_conn(pqxx::dbtransaction const &) noexcept;
  304. static PQXX_PRIVATE std::string errmsg(connection const *);
  305. static PQXX_PRIVATE std::string errmsg(dbtransaction const &tx)
  306. {
  307. return errmsg(&tx.conn());
  308. }
  309. PQXX_PRIVATE std::string errmsg() const { return errmsg(m_conn); }
  310. PQXX_PRIVATE std::int64_t seek(std::int64_t offset, int whence);
  311. std::size_t raw_read(std::byte buf[], std::size_t size);
  312. void raw_write(std::byte const buf[], std::size_t size);
  313. connection *m_conn = nullptr;
  314. int m_fd = -1;
  315. };
  316. } // namespace pqxx
  317. #endif