libpqxx  7.0.1
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 
40  largeobject() noexcept = default;
41 
43 
45  explicit largeobject(dbtransaction &t);
46 
48 
52  explicit largeobject(oid o) noexcept : m_id{o} {}
53 
55 
59  largeobject(dbtransaction &t, std::string_view file);
60 
62 
66  largeobject(largeobjectaccess const &o) noexcept;
67 
69 
73  [[nodiscard]] oid id() const noexcept { return m_id; }
74 
83 
85  [[nodiscard]] bool operator==(largeobject const &other) const
86  {
87  return m_id == other.m_id;
88  }
90 
91  [[nodiscard]] bool operator!=(largeobject const &other) const
92  {
93  return m_id != other.m_id;
94  }
96 
97  [[nodiscard]] bool operator<=(largeobject const &other) const
98  {
99  return m_id <= other.m_id;
100  }
102 
103  [[nodiscard]] bool operator>=(largeobject const &other) const
104  {
105  return m_id >= other.m_id;
106  }
108 
109  [[nodiscard]] bool operator<(largeobject const &other) const
110  {
111  return m_id < other.m_id;
112  }
114 
115  [[nodiscard]] bool operator>(largeobject const &other) const
116  {
117  return m_id > other.m_id;
118  }
120 
122 
126  void to_file(dbtransaction &t, std::string_view file) const;
127 
129 
133  void remove(dbtransaction &t) const;
134 
135 protected:
136  PQXX_PURE static internal::pq::PGconn *
137  raw_connection(dbtransaction const &T);
138 
139  PQXX_PRIVATE std::string reason(connection const &, int err) const;
140 
141 private:
142  oid m_id = oid_none;
143 };
144 
145 
147 class PQXX_LIBEXPORT largeobjectaccess : private largeobject
148 {
149 public:
153 
155 
159  using openmode = std::ios::openmode;
160 
162 
166  using seekdir = std::ios::seekdir;
167 
169 
173  explicit largeobjectaccess(
174  dbtransaction &t, openmode mode = std::ios::in | std::ios::out);
175 
177 
184  dbtransaction &t, oid o, openmode mode = std::ios::in | std::ios::out);
185 
187 
194  openmode mode = std::ios::in | std::ios::out);
195 
197 
203  dbtransaction &t, std::string_view file,
204  openmode mode = std::ios::in | std::ios::out);
205 
206  ~largeobjectaccess() noexcept { close(); }
207 
209 
212  using largeobject::id;
213 
215 
218  void to_file(std::string_view file) const
219  {
220  largeobject::to_file(m_trans, file);
221  }
222 
223  using largeobject::to_file;
224 
229 
235  void write(char const buf[], size_t len);
236 
238 
241  void write(std::string_view buf) { write(buf.data(), buf.size()); }
242 
244 
250  size_type read(char buf[], size_t len);
251 
253 
256  size_type seek(size_type dest, seekdir dir);
257 
259 
262  [[nodiscard]] size_type tell() const;
264 
277 
286  pos_type cseek(off_type dest, seekdir dir) noexcept;
287 
289 
295  off_type cwrite(char const buf[], size_t len) noexcept;
296 
298 
304  off_type cread(char buf[], size_t len) noexcept;
305 
307 
311  [[nodiscard]] pos_type ctell() const noexcept;
313 
318  void process_notice(std::string const &) noexcept;
321 
322  using largeobject::remove;
323 
324  using largeobject::operator==;
325  using largeobject::operator!=;
326  using largeobject::operator<;
327  using largeobject::operator<=;
328  using largeobject::operator>;
329  using largeobject::operator>=;
330 
331  largeobjectaccess() = delete;
332  largeobjectaccess(largeobjectaccess const &) = delete;
333  largeobjectaccess operator=(largeobjectaccess const &) = delete;
334 
335 private:
336  PQXX_PRIVATE std::string reason(int err) const;
337  internal::pq::PGconn *raw_connection() const
338  {
339  return largeobject::raw_connection(m_trans);
340  }
341 
342  PQXX_PRIVATE void open(openmode mode);
343  void close() noexcept;
344 
345  dbtransaction &m_trans;
346  int m_fd = -1;
347 };
348 
349 
351 
357 template<typename CHAR = char, typename TRAITS = std::char_traits<CHAR>>
358 class largeobject_streambuf : public std::basic_streambuf<CHAR, TRAITS>
359 {
360  using size_type = largeobject::size_type;
361 
362 public:
363  using char_type = CHAR;
364  using traits_type = TRAITS;
365  using int_type = typename traits_type::int_type;
366  using pos_type = typename traits_type::pos_type;
367  using off_type = typename traits_type::off_type;
370 
373  openmode mode = std::ios::in | std::ios::out, size_type buf_size = 512) :
374  m_bufsize{buf_size},
375  m_obj{t, o, mode},
376  m_g{nullptr},
377  m_p{nullptr}
378  {
379  initialize(mode);
380  }
381 
383  dbtransaction &t, oid o, openmode mode = std::ios::in | std::ios::out,
384  size_type buf_size = 512) :
385  m_bufsize{buf_size},
386  m_obj{t, o, mode},
387  m_g{nullptr},
388  m_p{nullptr}
389  {
390  initialize(mode);
391  }
392 
393  virtual ~largeobject_streambuf() noexcept
394  {
395  delete[] m_p;
396  delete[] m_g;
397  }
398 
399 
401  void process_notice(std::string const &s) { m_obj.process_notice(s); }
402 
403 protected:
404  virtual int sync() override
405  {
406  // setg() sets eback, gptr, egptr
407  this->setg(this->eback(), this->eback(), this->egptr());
408  return overflow(eof());
409  }
410 
411  virtual pos_type seekoff(off_type offset, seekdir dir, openmode) override
412  {
413  return adjust_eof(m_obj.cseek(largeobjectaccess::off_type(offset), dir));
414  }
415 
416  virtual pos_type seekpos(pos_type pos, openmode) override
417  {
418  largeobjectaccess::pos_type const newpos{
419  m_obj.cseek(largeobjectaccess::off_type(pos), std::ios::beg)};
420  return adjust_eof(newpos);
421  }
422 
423  virtual int_type overflow(int_type ch) override
424  {
425  char *const pp{this->pptr()};
426  if (pp == nullptr)
427  return eof();
428  char *const pb{this->pbase()};
429  int_type res{0};
430 
431  if (pp > pb)
432  {
433  auto const out{
434  adjust_eof(m_obj.cwrite(pb, static_cast<size_t>(pp - pb)))};
435  if constexpr (std::is_arithmetic_v<decltype(out)>)
436  res = check_cast<int_type>(out);
437  else
438  res = int_type(out);
439  }
440  this->setp(m_p, m_p + m_bufsize);
441 
442  // Write that one more character, if it's there.
443  if (ch != eof())
444  {
445  *this->pptr() = char(ch);
446  this->pbump(1);
447  }
448  return res;
449  }
450 
451  virtual int_type overflow() { return overflow(eof()); }
452 
453  virtual int_type underflow() override
454  {
455  if (this->gptr() == nullptr)
456  return eof();
457  char *const eb{this->eback()};
458  auto const res{int_type(
459  adjust_eof(m_obj.cread(this->eback(), static_cast<size_t>(m_bufsize))))};
460  this->setg(eb, eb, eb + ((res == eof()) ? 0 : res));
461  return ((res == 0) or (res == eof())) ? eof() : *eb;
462  }
463 
464 private:
466  static int_type eof() { return traits_type::eof(); }
467 
469  template<typename INTYPE> static std::streampos adjust_eof(INTYPE pos)
470  {
471  bool const at_eof{pos == -1};
472  if constexpr (std::is_arithmetic_v<std::streampos>)
473  {
474  return check_cast<std::streampos>(
475  (at_eof ? eof() : pos), "large object seek");
476  }
477  else
478  {
479  return std::streampos(at_eof ? eof() : pos);
480  }
481  }
482 
483  void initialize(openmode mode)
484  {
485  if ((mode & std::ios::in) != 0)
486  {
487  m_g = new char_type[unsigned(m_bufsize)];
488  this->setg(m_g, m_g, m_g);
489  }
490  if ((mode & std::ios::out) != 0)
491  {
492  m_p = new char_type[unsigned(m_bufsize)];
493  this->setp(m_p, m_p + m_bufsize);
494  }
495  }
496 
497  size_type const m_bufsize;
498  largeobjectaccess m_obj;
499 
501  char_type *m_g, *m_p;
502 };
503 
504 
506 
514 template<typename CHAR = char, typename TRAITS = std::char_traits<CHAR>>
515 class basic_ilostream : public std::basic_istream<CHAR, TRAITS>
516 {
517  using super = std::basic_istream<CHAR, TRAITS>;
518 
519 public:
520  using char_type = CHAR;
521  using traits_type = TRAITS;
522  using int_type = typename traits_type::int_type;
523  using pos_type = typename traits_type::pos_type;
524  using off_type = typename traits_type::off_type;
525 
527 
533  dbtransaction &t, largeobject o, largeobject::size_type buf_size = 512) :
534  super{nullptr},
535  m_buf{t, o, std::ios::in, buf_size}
536  {
537  super::init(&m_buf);
538  }
539 
541 
547  dbtransaction &t, oid o, largeobject::size_type buf_size = 512) :
548  super{nullptr},
549  m_buf{t, o, std::ios::in, buf_size}
550  {
551  super::init(&m_buf);
552  }
553 
554 private:
555  largeobject_streambuf<CHAR, TRAITS> m_buf;
556 };
557 
559 
560 
562 
570 template<typename CHAR = char, typename TRAITS = std::char_traits<CHAR>>
571 class basic_olostream : public std::basic_ostream<CHAR, TRAITS>
572 {
573  using super = std::basic_ostream<CHAR, TRAITS>;
574 
575 public:
576  using char_type = CHAR;
577  using traits_type = TRAITS;
578  using int_type = typename traits_type::int_type;
579  using pos_type = typename traits_type::pos_type;
580  using off_type = typename traits_type::off_type;
581 
583 
589  dbtransaction &t, largeobject o, largeobject::size_type buf_size = 512) :
590  super{nullptr},
591  m_buf{t, o, std::ios::out, buf_size}
592  {
593  super::init(&m_buf);
594  }
595 
597 
603  dbtransaction &t, oid o, largeobject::size_type buf_size = 512) :
604  super{nullptr},
605  m_buf{t, o, std::ios::out, buf_size}
606  {
607  super::init(&m_buf);
608  }
609 
611  {
612  try
613  {
614  m_buf.pubsync();
615  m_buf.pubsync();
616  }
617  catch (std::exception const &e)
618  {
619  m_buf.process_notice(e.what());
620  }
621  }
622 
623 private:
625 };
626 
628 
629 
631 
639 template<typename CHAR = char, typename TRAITS = std::char_traits<CHAR>>
640 class basic_lostream : public std::basic_iostream<CHAR, TRAITS>
641 {
642  using super = std::basic_iostream<CHAR, TRAITS>;
643 
644 public:
645  using char_type = CHAR;
646  using traits_type = TRAITS;
647  using int_type = typename traits_type::int_type;
648  using pos_type = typename traits_type::pos_type;
649  using off_type = typename traits_type::off_type;
650 
652 
658  dbtransaction &t, largeobject o, largeobject::size_type buf_size = 512) :
659  super{nullptr},
660  m_buf{t, o, std::ios::in | std::ios::out, buf_size}
661  {
662  super::init(&m_buf);
663  }
664 
666 
672  dbtransaction &t, oid o, largeobject::size_type buf_size = 512) :
673  super{nullptr},
674  m_buf{t, o, std::ios::in | std::ios::out, buf_size}
675  {
676  super::init(&m_buf);
677  }
678 
680  {
681  try
682  {
683  m_buf.pubsync();
684  m_buf.pubsync();
685  }
686  catch (std::exception const &e)
687  {
688  m_buf.process_notice(e.what());
689  }
690  }
691 
692 private:
694 };
695 
697 } // namespace pqxx
698 
699 #include "pqxx/internal/compiler-internal-post.hxx"
700 #endif
largeobjectaccess::openmode openmode
Definition: largeobject.hxx:368
std::ios::openmode openmode
Open mode: in, out (can be combined with the "or" operator)
Definition: largeobject.hxx:159
void to_file(dbtransaction &t, std::string_view file) const
Export large object's contents to a local file.
Definition: largeobject.cxx:98
Streambuf to use large objects in standard I/O streams.
Definition: largeobject.hxx:358
CHAR char_type
Definition: largeobject.hxx:520
largeobject_streambuf(dbtransaction &t, largeobject o, openmode mode=std::ios::in|std::ios::out, size_type buf_size=512)
Definition: largeobject.hxx:371
typename traits_type::pos_type pos_type
Definition: largeobject.hxx:523
CHAR char_type
Definition: largeobject.hxx:363
basic_olostream(dbtransaction &t, largeobject o, largeobject::size_type buf_size=512)
Create a basic_olostream.
Definition: largeobject.hxx:588
~basic_olostream()
Definition: largeobject.hxx:610
Output stream that writes data back to a large object.
Definition: largeobject.hxx:571
bool operator!=(largeobject const &other) const
Compare object identities.
Definition: largeobject.hxx:91
TRAITS traits_type
Definition: largeobject.hxx:646
bool operator<=(largeobject const &other) const
Compare object identities.
Definition: largeobject.hxx:97
basic_lostream(dbtransaction &t, largeobject o, largeobject::size_type buf_size=512)
Create a basic_lostream.
Definition: largeobject.hxx:657
virtual pos_type seekoff(off_type offset, seekdir dir, openmode) override
Definition: largeobject.hxx:411
bool operator<(largeobject const &other) const
Compare object identities.
Definition: largeobject.hxx:109
basic_ilostream(dbtransaction &t, largeobject o, largeobject::size_type buf_size=512)
Create a basic_ilostream.
Definition: largeobject.hxx:532
std::ios::seekdir seekdir
Seek direction: beg, cur, end.
Definition: largeobject.hxx:166
CHAR char_type
Definition: largeobject.hxx:645
bool operator>(largeobject const &other) const
Compare object identities.
Definition: largeobject.hxx:115
typename traits_type::int_type int_type
Definition: largeobject.hxx:522
typename traits_type::off_type off_type
Definition: largeobject.hxx:580
void to_file(std::string_view file) const
Export large object's contents to a local file.
Definition: largeobject.hxx:218
~largeobjectaccess() noexcept
Definition: largeobject.hxx:206
TRAITS traits_type
Definition: largeobject.hxx:577
void write(std::string_view buf)
Write string to large object.
Definition: largeobject.hxx:241
static PQXX_PURE internal::pq::PGconn * raw_connection(dbtransaction const &T)
Definition: largeobject.cxx:127
typename traits_type::off_type off_type
Definition: largeobject.hxx:649
Input stream that gets its data from a large object.
Definition: largeobject.hxx:515
Abstract transaction base class: bracket transactions on the database.
Definition: dbtransaction.hxx:52
virtual int_type overflow(int_type ch) override
Definition: largeobject.hxx:423
TRAITS traits_type
Definition: largeobject.hxx:521
basic_olostream(dbtransaction &t, oid o, largeobject::size_type buf_size=512)
Create a basic_olostream.
Definition: largeobject.hxx:602
TRAITS traits_type
Definition: largeobject.hxx:364
virtual int_type overflow()
Definition: largeobject.hxx:451
void process_notice(std::string const &s)
For use by large object stream classes.
Definition: largeobject.hxx:401
typename traits_type::int_type int_type
Definition: largeobject.hxx:365
virtual int_type underflow() override
Definition: largeobject.hxx:453
~basic_lostream()
Definition: largeobject.hxx:679
largeobjectaccess::seekdir seekdir
Definition: largeobject.hxx:369
bool operator==(largeobject const &other) const
Compare object identities.
Definition: largeobject.hxx:85
Stream that reads and writes a large object.
Definition: largeobject.hxx:640
basic_lostream(dbtransaction &t, oid o, largeobject::size_type buf_size=512)
Create a basic_lostream.
Definition: largeobject.hxx:671
constexpr oid oid_none
The "null" oid.
Definition: util.hxx:179
typename traits_type::int_type int_type
Definition: largeobject.hxx:578
basic_ilostream(dbtransaction &t, oid o, largeobject::size_type buf_size=512)
Create a basic_ilostream.
Definition: largeobject.hxx:546
virtual ~largeobject_streambuf() noexcept
Definition: largeobject.hxx:393
typename traits_type::int_type int_type
Definition: largeobject.hxx:647
typename traits_type::off_type off_type
Definition: largeobject.hxx:367
Accessor for large object's contents.
Definition: largeobject.hxx:147
bool operator>=(largeobject const &other) const
Compare object identities.
Definition: largeobject.hxx:103
virtual int sync() override
Definition: largeobject.hxx:404
large_object_size_type size_type
Definition: largeobject.hxx:37
Dedicated namespace for helper types related to prepared statements.
Definition: array.hxx:25
virtual pos_type seekpos(pos_type pos, openmode) override
Definition: largeobject.hxx:416
typename traits_type::off_type off_type
Definition: largeobject.hxx:524
CHAR char_type
Definition: largeobject.hxx:576
size_type off_type
Definition: largeobject.hxx:151
Identity of a large object.
Definition: largeobject.hxx:34
typename traits_type::pos_type pos_type
Definition: largeobject.hxx:648
typename traits_type::pos_type pos_type
Definition: largeobject.hxx:579
int64_t large_object_size_type
Number of bytes in a large object.
Definition: types.hxx:33
size_type pos_type
Definition: largeobject.hxx:152
typename traits_type::pos_type pos_type
Definition: largeobject.hxx:366
largeobject_streambuf(dbtransaction &t, oid o, openmode mode=std::ios::in|std::ios::out, size_type buf_size=512)
Definition: largeobject.hxx:382
oid id() const noexcept
Object identifier.
Definition: largeobject.hxx:73