libpqxx  7.2.0
largeobject.hxx
1 /* Large Objects interface.
2  *
3  * Allows access to large objects directly, or through I/O streams.
4  *
5  * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/largeobject instead.
6  *
7  * Copyright (c) 2000-2020, 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_LARGEOBJECT
14 #define PQXX_H_LARGEOBJECT
15 
16 #include "pqxx/compiler-public.hxx"
17 #include "pqxx/internal/compiler-internal-pre.hxx"
18 
19 #include <streambuf>
20 
21 #include "pqxx/dbtransaction.hxx"
22 
23 
24 namespace pqxx
25 {
27 
34 class PQXX_LIBEXPORT largeobject
35 {
36 public:
38 
41  largeobject() noexcept = default;
42 
44 
46  explicit largeobject(dbtransaction &t);
47 
49 
53  explicit largeobject(oid o) noexcept : m_id{o} {}
54 
56 
60  largeobject(dbtransaction &t, std::string_view file);
61 
63 
67  largeobject(largeobjectaccess const &o) noexcept;
68 
70 
74  [[nodiscard]] oid id() const noexcept { return m_id; }
75 
84 
86  [[nodiscard]] bool operator==(largeobject const &other) const
87  {
88  return m_id == other.m_id;
89  }
91 
92  [[nodiscard]] bool operator!=(largeobject const &other) const
93  {
94  return m_id != other.m_id;
95  }
97 
98  [[nodiscard]] bool operator<=(largeobject const &other) const
99  {
100  return m_id <= other.m_id;
101  }
103 
104  [[nodiscard]] bool operator>=(largeobject const &other) const
105  {
106  return m_id >= other.m_id;
107  }
109 
110  [[nodiscard]] bool operator<(largeobject const &other) const
111  {
112  return m_id < other.m_id;
113  }
115 
116  [[nodiscard]] bool operator>(largeobject const &other) const
117  {
118  return m_id > other.m_id;
119  }
121 
123 
127  void to_file(dbtransaction &t, std::string_view file) const;
128 
130 
134  void remove(dbtransaction &t) const;
135 
136 protected:
137  PQXX_PURE static internal::pq::PGconn *
138  raw_connection(dbtransaction const &T);
139 
140  PQXX_PRIVATE std::string reason(connection const &, int err) const;
141 
142 private:
143  oid m_id = oid_none;
144 };
145 
146 
148 class PQXX_LIBEXPORT largeobjectaccess : private largeobject
149 {
150 public:
154 
156 
163  using openmode = std::ios::openmode;
164 
166  static constexpr auto default_mode{
167  std::ios::in | std::ios::out | std::ios::binary};
168 
170  using seekdir = std::ios::seekdir;
171 
173 
178  explicit largeobjectaccess(dbtransaction &t, openmode mode = default_mode);
179 
181 
188  largeobjectaccess(dbtransaction &t, oid o, openmode mode = default_mode);
189 
191 
198  dbtransaction &t, largeobject o, openmode mode = default_mode);
199 
201 
207  dbtransaction &t, std::string_view file, openmode mode = default_mode);
208 
209  ~largeobjectaccess() noexcept { close(); }
210 
212 
215  using largeobject::id;
216 
218 
221  void to_file(std::string_view file) const
222  {
223  largeobject::to_file(m_trans, file);
224  }
225 
226  using largeobject::to_file;
227 
232 
238  void write(char const buf[], std::size_t len);
239 
241 
244  void write(std::string_view buf) { write(buf.data(), std::size(buf)); }
245 
247 
253  size_type read(char buf[], std::size_t len);
254 
256 
259  size_type seek(size_type dest, seekdir dir);
260 
262 
265  [[nodiscard]] size_type tell() const;
267 
280 
289  pos_type cseek(off_type dest, seekdir dir) noexcept;
290 
292 
298  off_type cwrite(char const buf[], std::size_t len) noexcept;
299 
301 
307  off_type cread(char buf[], std::size_t len) noexcept;
308 
310 
314  [[nodiscard]] pos_type ctell() const noexcept;
316 
321  void process_notice(std::string const &) noexcept;
324 
325  using largeobject::remove;
326 
327  using largeobject::operator==;
328  using largeobject::operator!=;
329  using largeobject::operator<;
330  using largeobject::operator<=;
331  using largeobject::operator>;
332  using largeobject::operator>=;
333 
334  largeobjectaccess() = delete;
335  largeobjectaccess(largeobjectaccess const &) = delete;
336  largeobjectaccess operator=(largeobjectaccess const &) = delete;
337 
338 private:
339  PQXX_PRIVATE std::string reason(int err) const;
340  internal::pq::PGconn *raw_connection() const
341  {
342  return largeobject::raw_connection(m_trans);
343  }
344 
345  PQXX_PRIVATE void open(openmode mode);
346  void close() noexcept;
347 
348  dbtransaction &m_trans;
349  int m_fd = -1;
350 };
351 
352 
354 
362 template<typename CHAR = char, typename TRAITS = std::char_traits<CHAR>>
363 class largeobject_streambuf : public std::basic_streambuf<CHAR, TRAITS>
364 {
365  using size_type = largeobject::size_type;
366 
367 public:
368  using char_type = CHAR;
369  using traits_type = TRAITS;
370  using int_type = typename traits_type::int_type;
371  using pos_type = typename traits_type::pos_type;
372  using off_type = typename traits_type::off_type;
375 
377  static constexpr auto default_mode{
378  std::ios::in | std::ios::out | std::ios::binary};
379 
381  dbtransaction &t, largeobject o, openmode mode = default_mode,
382  size_type buf_size = 512) :
383  m_bufsize{buf_size}, m_obj{t, o, mode}, m_g{nullptr}, m_p{nullptr}
384  {
385  initialize(mode);
386  }
387 
389  dbtransaction &t, oid o, openmode mode = default_mode,
390  size_type buf_size = 512) :
391  m_bufsize{buf_size}, m_obj{t, o, mode}, m_g{nullptr}, m_p{nullptr}
392  {
393  initialize(mode);
394  }
395 
396  virtual ~largeobject_streambuf() noexcept
397  {
398  delete[] m_p;
399  delete[] m_g;
400  }
401 
403  void process_notice(std::string const &s) { m_obj.process_notice(s); }
404 
405 protected:
406  virtual int sync() override
407  {
408  // setg() sets eback, gptr, egptr.
409  this->setg(this->eback(), this->eback(), this->egptr());
410  return overflow(eof());
411  }
412 
413  virtual pos_type seekoff(off_type offset, seekdir dir, openmode) override
414  {
415  return adjust_eof(m_obj.cseek(largeobjectaccess::off_type(offset), dir));
416  }
417 
418  virtual pos_type seekpos(pos_type pos, openmode) override
419  {
420  largeobjectaccess::pos_type const newpos{
421  m_obj.cseek(largeobjectaccess::off_type(pos), std::ios::beg)};
422  return adjust_eof(newpos);
423  }
424 
425  virtual int_type overflow(int_type ch) override
426  {
427  auto *const pp{this->pptr()};
428  if (pp == nullptr)
429  return eof();
430  auto *const pb{this->pbase()};
431  int_type res{0};
432 
433  if (pp > pb)
434  {
435  auto const out{
436  adjust_eof(m_obj.cwrite(pb, static_cast<std::size_t>(pp - pb)))};
437  if constexpr (std::is_arithmetic_v<decltype(out)>)
438  res = check_cast<int_type>(out);
439  else
440  res = int_type(out);
441  }
442  this->setp(m_p, m_p + m_bufsize);
443 
444  // Write that one more character, if it's there.
445  if (ch != eof())
446  {
447  *this->pptr() = static_cast<char_type>(ch);
448  this->pbump(1);
449  }
450  return res;
451  }
452 
453  virtual int_type overflow() { return overflow(eof()); }
454 
455  virtual int_type underflow() override
456  {
457  if (this->gptr() == nullptr)
458  return eof();
459  auto *const eb{this->eback()};
460  auto const res{adjust_eof(
461  m_obj.cread(this->eback(), static_cast<std::size_t>(m_bufsize)))};
462  this->setg(
463  eb, eb, eb + (res == eof() ? 0 : static_cast<std::size_t>(res)));
464  return (res == eof() or res == 0) ? eof() : traits_type::to_int_type(*eb);
465  }
466 
467 private:
469  static int_type eof() { return traits_type::eof(); }
470 
472  template<typename INTYPE> static std::streampos adjust_eof(INTYPE pos)
473  {
474  bool const at_eof{pos == -1};
475  if constexpr (std::is_arithmetic_v<std::streampos>)
476  {
477  return check_cast<std::streampos>(
478  (at_eof ? eof() : pos), "large object seek");
479  }
480  else
481  {
482  return std::streampos(at_eof ? eof() : pos);
483  }
484  }
485 
486  void initialize(openmode mode)
487  {
488  if ((mode & std::ios::in) != 0)
489  {
490  m_g = new char_type[unsigned(m_bufsize)];
491  this->setg(m_g, m_g, m_g);
492  }
493  if ((mode & std::ios::out) != 0)
494  {
495  m_p = new char_type[unsigned(m_bufsize)];
496  this->setp(m_p, m_p + m_bufsize);
497  }
498  }
499 
500  size_type const m_bufsize;
501  largeobjectaccess m_obj;
502 
504  char_type *m_g, *m_p;
505 };
506 
507 
509 
517 template<typename CHAR = char, typename TRAITS = std::char_traits<CHAR>>
518 class basic_ilostream : public std::basic_istream<CHAR, TRAITS>
519 {
520  using super = std::basic_istream<CHAR, TRAITS>;
521 
522 public:
523  using char_type = CHAR;
524  using traits_type = TRAITS;
525  using int_type = typename traits_type::int_type;
526  using pos_type = typename traits_type::pos_type;
527  using off_type = typename traits_type::off_type;
528 
530 
536  dbtransaction &t, largeobject o, largeobject::size_type buf_size = 512) :
537  super{nullptr},
538  m_buf{t, o, std::ios::in | std::ios::binary, buf_size}
539  {
540  super::init(&m_buf);
541  }
542 
544 
550  dbtransaction &t, oid o, largeobject::size_type buf_size = 512) :
551  super{nullptr},
552  m_buf{t, o, std::ios::in | std::ios::binary, buf_size}
553  {
554  super::init(&m_buf);
555  }
556 
557 private:
559 };
560 
562 
563 
565 
573 template<typename CHAR = char, typename TRAITS = std::char_traits<CHAR>>
574 class basic_olostream : public std::basic_ostream<CHAR, TRAITS>
575 {
576  using super = std::basic_ostream<CHAR, TRAITS>;
577 
578 public:
579  using char_type = CHAR;
580  using traits_type = TRAITS;
581  using int_type = typename traits_type::int_type;
582  using pos_type = typename traits_type::pos_type;
583  using off_type = typename traits_type::off_type;
584 
586 
592  dbtransaction &t, largeobject o, largeobject::size_type buf_size = 512) :
593  super{nullptr},
594  m_buf{t, o, std::ios::out | std::ios::binary, buf_size}
595  {
596  super::init(&m_buf);
597  }
598 
600 
606  dbtransaction &t, oid o, largeobject::size_type buf_size = 512) :
607  super{nullptr},
608  m_buf{t, o, std::ios::out | std::ios::binary, buf_size}
609  {
610  super::init(&m_buf);
611  }
612 
614  {
615  try
616  {
617  m_buf.pubsync();
618  m_buf.pubsync();
619  }
620  catch (std::exception const &e)
621  {
622  m_buf.process_notice(e.what());
623  }
624  }
625 
626 private:
628 };
629 
631 
632 
634 
642 template<typename CHAR = char, typename TRAITS = std::char_traits<CHAR>>
643 class basic_lostream : public std::basic_iostream<CHAR, TRAITS>
644 {
645  using super = std::basic_iostream<CHAR, TRAITS>;
646 
647 public:
648  using char_type = CHAR;
649  using traits_type = TRAITS;
650  using int_type = typename traits_type::int_type;
651  using pos_type = typename traits_type::pos_type;
652  using off_type = typename traits_type::off_type;
653 
655 
661  dbtransaction &t, largeobject o, largeobject::size_type buf_size = 512) :
662  super{nullptr},
663  m_buf{
664  t, o, std::ios::in | std::ios::out | std::ios::binary, buf_size}
665  {
666  super::init(&m_buf);
667  }
668 
670 
676  dbtransaction &t, oid o, largeobject::size_type buf_size = 512) :
677  super{nullptr},
678  m_buf{
679  t, o, std::ios::in | std::ios::out | std::ios::binary, buf_size}
680  {
681  super::init(&m_buf);
682  }
683 
685  {
686  try
687  {
688  m_buf.pubsync();
689  m_buf.pubsync();
690  }
691  catch (std::exception const &e)
692  {
693  m_buf.process_notice(e.what());
694  }
695  }
696 
697 private:
699 };
700 
702 } // namespace pqxx
703 
704 #include "pqxx/internal/compiler-internal-post.hxx"
705 #endif
virtual pos_type seekoff(off_type offset, seekdir dir, openmode) override
Definition: largeobject.hxx:413
virtual ~largeobject_streambuf() noexcept
Definition: largeobject.hxx:396
basic_olostream(dbtransaction &t, largeobject o, largeobject::size_type buf_size=512)
Create a basic_olostream.
Definition: largeobject.hxx:591
TRAITS traits_type
Definition: largeobject.hxx:524
largeobject_streambuf(dbtransaction &t, oid o, openmode mode=default_mode, size_type buf_size=512)
Definition: largeobject.hxx:388
TRAITS traits_type
Definition: largeobject.hxx:649
virtual int sync() override
Definition: largeobject.hxx:406
typename traits_type::off_type off_type
Definition: largeobject.hxx:583
int64_t large_object_size_type
Number of bytes in a large object.
Definition: types.hxx:33
Accessor for large object&#39;s contents.
Definition: largeobject.hxx:148
bool operator>=(largeobject const &other) const
Compare object identities.
Definition: largeobject.hxx:104
large_object_size_type size_type
Definition: largeobject.hxx:37
basic_lostream(dbtransaction &t, oid o, largeobject::size_type buf_size=512)
Create a basic_lostream.
Definition: largeobject.hxx:675
bool operator==(largeobject const &other) const
Compare object identities.
Definition: largeobject.hxx:86
~basic_olostream()
Definition: largeobject.hxx:613
TO check_cast(FROM value, char const description[])
Cast a numeric value to another type, or throw if it underflows/overflows.
Definition: util.hxx:53
Input stream that gets its data from a large object.
Definition: largeobject.hxx:518
bool operator>(largeobject const &other) const
Compare object identities.
Definition: largeobject.hxx:116
bool operator<(largeobject const &other) const
Compare object identities.
Definition: largeobject.hxx:110
Connection to a database.
Definition: connection.hxx:164
typename traits_type::pos_type pos_type
Definition: largeobject.hxx:526
size_type pos_type
Definition: largeobject.hxx:153
static PQXX_PURE internal::pq::PGconn * raw_connection(dbtransaction const &T)
Definition: largeobject.cxx:133
basic_ilostream(dbtransaction &t, largeobject o, largeobject::size_type buf_size=512)
Create a basic_ilostream.
Definition: largeobject.hxx:535
The home of all libpqxx classes, functions, templates, etc.
Definition: array.hxx:25
void remove(dbtransaction &t) const
Delete large object from database.
Definition: largeobject.cxx:116
Abstract transaction base class: bracket transactions on the database.
Definition: dbtransaction.hxx:52
oid id() const noexcept
Object identifier.
Definition: largeobject.hxx:74
Identity of a large object.
Definition: largeobject.hxx:34
constexpr oid oid_none
The "null" oid.
Definition: util.hxx:188
TRAITS traits_type
Definition: largeobject.hxx:580
typename traits_type::off_type off_type
Definition: largeobject.hxx:527
std::ios::seekdir seekdir
Seek direction: beg, cur, end.
Definition: largeobject.hxx:170
virtual pos_type seekpos(pos_type pos, openmode) override
Definition: largeobject.hxx:418
typename traits_type::int_type int_type
Definition: largeobject.hxx:650
typename traits_type::int_type int_type
Definition: largeobject.hxx:581
Stream that reads and writes a large object.
Definition: largeobject.hxx:643
typename traits_type::pos_type pos_type
Definition: largeobject.hxx:651
Streambuf to use large objects in standard I/O streams.
Definition: largeobject.hxx:363
basic_olostream(dbtransaction &t, oid o, largeobject::size_type buf_size=512)
Create a basic_olostream.
Definition: largeobject.hxx:605
large_object_size_type size_type
Definition: largeobject.hxx:37
CHAR char_type
Definition: largeobject.hxx:579
typename traits_type::int_type int_type
Definition: largeobject.hxx:525
bool operator<=(largeobject const &other) const
Compare object identities.
Definition: largeobject.hxx:98
virtual int_type overflow(int_type ch) override
Definition: largeobject.hxx:425
Output stream that writes data back to a large object.
Definition: largeobject.hxx:574
void to_file(dbtransaction &t, std::string_view file) const
Export large object&#39;s contents to a local file.
Definition: largeobject.cxx:98
TRAITS traits_type
Definition: largeobject.hxx:369
size_type off_type
Definition: largeobject.hxx:152
typename traits_type::pos_type pos_type
Definition: largeobject.hxx:371
~basic_lostream()
Definition: largeobject.hxx:684
void process_notice(std::string const &s)
For use by large object stream classes.
Definition: largeobject.hxx:403
typename traits_type::off_type off_type
Definition: largeobject.hxx:652
CHAR char_type
Definition: largeobject.hxx:648
void to_file(std::string_view file) const
Export large object&#39;s contents to a local file.
Definition: largeobject.hxx:221
largeobjectaccess::openmode openmode
Definition: largeobject.hxx:373
std::ios::openmode openmode
Open mode: in, out (can be combined using "bitwise or").
Definition: largeobject.hxx:163
CHAR char_type
Definition: largeobject.hxx:523
virtual int_type overflow()
Definition: largeobject.hxx:453
basic_lostream(dbtransaction &t, largeobject o, largeobject::size_type buf_size=512)
Create a basic_lostream.
Definition: largeobject.hxx:660
largeobject_streambuf(dbtransaction &t, largeobject o, openmode mode=default_mode, size_type buf_size=512)
Definition: largeobject.hxx:380
virtual int_type underflow() override
Definition: largeobject.hxx:455
bool operator!=(largeobject const &other) const
Compare object identities.
Definition: largeobject.hxx:92
typename traits_type::off_type off_type
Definition: largeobject.hxx:372
basic_ilostream(dbtransaction &t, oid o, largeobject::size_type buf_size=512)
Create a basic_ilostream.
Definition: largeobject.hxx:549
largeobjectaccess::seekdir seekdir
Definition: largeobject.hxx:374
typename traits_type::pos_type pos_type
Definition: largeobject.hxx:582
~largeobjectaccess() noexcept
Definition: largeobject.hxx:209
CHAR char_type
Definition: largeobject.hxx:368
typename traits_type::int_type int_type
Definition: largeobject.hxx:370
void write(std::string_view buf)
Write string to large object.
Definition: largeobject.hxx:244