libpqxx  7.3.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(zview) 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;
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(zview 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 write_sz{pp - pb};
436  auto const written_sz{
437  m_obj.cwrite(pb, static_cast<std::size_t>(pp - pb))};
438  if (written_sz <= static_cast<off_type>(0))
439  throw internal_error{
440  "pqxx::largeobject: write failed "
441  "(is transaction still valid on write or flush?), "
442  "libpq reports error"};
443  else if (write_sz != written_sz)
444  throw internal_error{
445  "pqxx::largeobject: write failed "
446  "(is transaction still valid on write or flush?), " +
447  std::to_string(written_sz) + "/" + std::to_string(write_sz) +
448  " bytes written"};
449  auto const out{adjust_eof(written_sz)};
450 
451  if constexpr (std::is_arithmetic_v<decltype(out)>)
452  res = check_cast<int_type>(out, "largeobject position"sv);
453  else
454  res = int_type(out);
455  }
456  this->setp(m_p, m_p + m_bufsize);
457 
458  // Write that one more character, if it's there.
459  if (ch != eof())
460  {
461  *this->pptr() = static_cast<char_type>(ch);
462  this->pbump(1);
463  }
464  return res;
465  }
466 
467  virtual int_type overflow() { return overflow(eof()); }
468 
469  virtual int_type underflow() override
470  {
471  if (this->gptr() == nullptr)
472  return eof();
473  auto *const eb{this->eback()};
474  auto const res{adjust_eof(
475  m_obj.cread(this->eback(), static_cast<std::size_t>(m_bufsize)))};
476  this->setg(
477  eb, eb, eb + (res == eof() ? 0 : static_cast<std::size_t>(res)));
478  return (res == eof() or res == 0) ? eof() : traits_type::to_int_type(*eb);
479  }
480 
481 private:
483  static int_type eof() { return traits_type::eof(); }
484 
486  template<typename INTYPE> static std::streampos adjust_eof(INTYPE pos)
487  {
488  bool const at_eof{pos == -1};
489  if constexpr (std::is_arithmetic_v<std::streampos>)
490  {
491  return check_cast<std::streampos>(
492  (at_eof ? eof() : pos), "large object seek"sv);
493  }
494  else
495  {
496  return std::streampos(at_eof ? eof() : pos);
497  }
498  }
499 
500  void initialize(openmode mode)
501  {
502  if ((mode & std::ios::in) != 0)
503  {
504  m_g = new char_type[unsigned(m_bufsize)];
505  this->setg(m_g, m_g, m_g);
506  }
507  if ((mode & std::ios::out) != 0)
508  {
509  m_p = new char_type[unsigned(m_bufsize)];
510  this->setp(m_p, m_p + m_bufsize);
511  }
512  }
513 
514  size_type const m_bufsize;
515  largeobjectaccess m_obj;
516 
518  char_type *m_g, *m_p;
519 };
520 
521 
523 
531 template<typename CHAR = char, typename TRAITS = std::char_traits<CHAR>>
532 class basic_ilostream : public std::basic_istream<CHAR, TRAITS>
533 {
534  using super = std::basic_istream<CHAR, TRAITS>;
535 
536 public:
537  using char_type = CHAR;
538  using traits_type = TRAITS;
539  using int_type = typename traits_type::int_type;
540  using pos_type = typename traits_type::pos_type;
541  using off_type = typename traits_type::off_type;
542 
544 
550  dbtransaction &t, largeobject 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 
558 
564  dbtransaction &t, oid o, largeobject::size_type buf_size = 512) :
565  super{nullptr},
566  m_buf{t, o, std::ios::in | std::ios::binary, buf_size}
567  {
568  super::init(&m_buf);
569  }
570 
571 private:
572  largeobject_streambuf<CHAR, TRAITS> m_buf;
573 };
574 
576 
577 
579 
587 template<typename CHAR = char, typename TRAITS = std::char_traits<CHAR>>
588 class basic_olostream : public std::basic_ostream<CHAR, TRAITS>
589 {
590  using super = std::basic_ostream<CHAR, TRAITS>;
591 
592 public:
593  using char_type = CHAR;
594  using traits_type = TRAITS;
595  using int_type = typename traits_type::int_type;
596  using pos_type = typename traits_type::pos_type;
597  using off_type = typename traits_type::off_type;
598 
600 
606  dbtransaction &t, largeobject 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 
620  dbtransaction &t, oid o, largeobject::size_type buf_size = 512) :
621  super{nullptr},
622  m_buf{t, o, std::ios::out | std::ios::binary, buf_size}
623  {
624  super::init(&m_buf);
625  }
626 
628  {
629  try
630  {
631  m_buf.pubsync();
632  m_buf.pubsync();
633  }
634  catch (std::exception const &e)
635  {
636  m_buf.process_notice(e.what());
637  }
638  }
639 
640 private:
642 };
643 
645 
646 
648 
656 template<typename CHAR = char, typename TRAITS = std::char_traits<CHAR>>
657 class basic_lostream : public std::basic_iostream<CHAR, TRAITS>
658 {
659  using super = std::basic_iostream<CHAR, TRAITS>;
660 
661 public:
662  using char_type = CHAR;
663  using traits_type = TRAITS;
664  using int_type = typename traits_type::int_type;
665  using pos_type = typename traits_type::pos_type;
666  using off_type = typename traits_type::off_type;
667 
669 
675  dbtransaction &t, largeobject o, largeobject::size_type buf_size = 512) :
676  super{nullptr},
677  m_buf{
678  t, o, std::ios::in | std::ios::out | std::ios::binary, buf_size}
679  {
680  super::init(&m_buf);
681  }
682 
684 
690  dbtransaction &t, oid o, largeobject::size_type buf_size = 512) :
691  super{nullptr},
692  m_buf{
693  t, o, std::ios::in | std::ios::out | std::ios::binary, buf_size}
694  {
695  super::init(&m_buf);
696  }
697 
699  {
700  try
701  {
702  m_buf.pubsync();
703  m_buf.pubsync();
704  }
705  catch (std::exception const &e)
706  {
707  m_buf.process_notice(e.what());
708  }
709  }
710 
711 private:
713 };
714 
716 } // namespace pqxx
717 
718 #include "pqxx/internal/compiler-internal-post.hxx"
719 #endif
pqxx::largeobject::raw_connection
static PQXX_PURE internal::pq::PGconn * raw_connection(dbtransaction const &T)
Definition: largeobject.cxx:132
pqxx::largeobjectaccess::size_type
large_object_size_type size_type
Definition: largeobject.hxx:37
pqxx::basic_olostream::off_type
typename traits_type::off_type off_type
Definition: largeobject.hxx:597
pqxx::basic_olostream::int_type
typename traits_type::int_type int_type
Definition: largeobject.hxx:595
pqxx::dbtransaction
Abstract transaction base class: bracket transactions on the database.
Definition: dbtransaction.hxx:53
pqxx::largeobjectaccess::to_file
void to_file(std::string_view file) const
Export large object's contents to a local file.
Definition: largeobject.hxx:221
pqxx::basic_lostream
Stream that reads and writes a large object.
Definition: largeobject.hxx:658
pqxx::largeobjectaccess::cwrite
off_type cwrite(char const buf[], std::size_t len) noexcept
Write to large object's data stream.
Definition: largeobject.cxx:205
pqxx::largeobject_streambuf
Streambuf to use large objects in standard I/O streams.
Definition: largeobject.hxx:364
pqxx::largeobjectaccess::read
size_type read(char buf[], std::size_t len)
Read data from large object.
Definition: largeobject.cxx:249
pqxx
The home of all libpqxx classes, functions, templates, etc.
Definition: array.hxx:26
pqxx::basic_ilostream::off_type
typename traits_type::off_type off_type
Definition: largeobject.hxx:541
pqxx::largeobject_streambuf::seekoff
virtual pos_type seekoff(off_type offset, seekdir dir, openmode) override
Definition: largeobject.hxx:413
pqxx::largeobject::reason
std::string reason(connection const &, int err) const
Definition: largeobject.cxx:139
pqxx::basic_olostream::~basic_olostream
~basic_olostream()
Definition: largeobject.hxx:627
pqxx::basic_ilostream::pos_type
typename traits_type::pos_type pos_type
Definition: largeobject.hxx:540
pqxx::largeobjectaccess::cread
off_type cread(char buf[], std::size_t len) noexcept
Read from large object's data stream.
Definition: largeobject.cxx:212
pqxx::largeobjectaccess::openmode
std::ios::openmode openmode
Open mode: in, out (can be combined using "bitwise or").
Definition: largeobject.hxx:163
pqxx::largeobjectaccess::tell
size_type tell() const
Report current position in large object's data stream.
Definition: largeobject.cxx:289
pqxx::largeobject::largeobject
largeobject() noexcept=default
pqxx::largeobjectaccess::~largeobjectaccess
~largeobjectaccess() noexcept
Definition: largeobject.hxx:209
pqxx::basic_lostream::basic_lostream
basic_lostream(dbtransaction &t, oid o, largeobject::size_type buf_size=512)
Create a basic_lostream.
Definition: largeobject.hxx:689
pqxx::largeobject_streambuf::largeobject_streambuf
largeobject_streambuf(dbtransaction &t, oid o, openmode mode=default_mode, size_type buf_size=512)
Definition: largeobject.hxx:388
pqxx::largeobjectaccess::seek
size_type seek(size_type dest, seekdir dir)
Seek in large object's data stream.
Definition: largeobject.cxx:179
pqxx::basic_olostream::basic_olostream
basic_olostream(dbtransaction &t, oid o, largeobject::size_type buf_size=512)
Create a basic_olostream.
Definition: largeobject.hxx:619
pqxx::basic_ilostream::basic_ilostream
basic_ilostream(dbtransaction &t, largeobject o, largeobject::size_type buf_size=512)
Create a basic_ilostream.
Definition: largeobject.hxx:549
pqxx::largeobjectaccess
Accessor for large object's contents.
Definition: largeobject.hxx:149
pqxx::basic_ilostream::traits_type
TRAITS traits_type
Definition: largeobject.hxx:538
pqxx::largeobject_streambuf::underflow
virtual int_type underflow() override
Definition: largeobject.hxx:469
pqxx::largeobject_streambuf::sync
virtual int sync() override
Definition: largeobject.hxx:406
pqxx::basic_ilostream::basic_ilostream
basic_ilostream(dbtransaction &t, oid o, largeobject::size_type buf_size=512)
Create a basic_ilostream.
Definition: largeobject.hxx:563
pqxx::largeobject_streambuf::~largeobject_streambuf
virtual ~largeobject_streambuf() noexcept
Definition: largeobject.hxx:396
pqxx::largeobject::size_type
large_object_size_type size_type
Definition: largeobject.hxx:37
pqxx::connection
Connection to a database.
Definition: connection.hxx:164
pqxx::basic_lostream::~basic_lostream
~basic_lostream()
Definition: largeobject.hxx:698
pqxx::largeobject
Identity of a large object.
Definition: largeobject.hxx:35
pqxx::basic_lostream::pos_type
typename traits_type::pos_type pos_type
Definition: largeobject.hxx:665
pqxx::basic_olostream::char_type
CHAR char_type
Definition: largeobject.hxx:593
pqxx::largeobjectaccess::ctell
pos_type ctell() const noexcept
Report current position in large object's data stream.
Definition: largeobject.cxx:219
pqxx::internal_error
Internal error in libpqxx library.
Definition: except.hxx:158
pqxx::largeobject_streambuf::process_notice
void process_notice(zview const &s)
For use by large object stream classes.
Definition: largeobject.hxx:403
pqxx::largeobjectaccess::seekdir
std::ios::seekdir seekdir
Seek direction: beg, cur, end.
Definition: largeobject.hxx:170
pqxx::largeobject_streambuf::seekpos
virtual pos_type seekpos(pos_type pos, openmode) override
Definition: largeobject.hxx:418
pqxx::largeobject::remove
void remove(dbtransaction &t) const
Delete large object from database.
Definition: largeobject.cxx:116
pqxx::largeobject_streambuf< char, std::char_traits< char > >::pos_type
typename traits_type::pos_type pos_type
Definition: largeobject.hxx:371
pqxx::usage_error
Error in usage of libpqxx library, similar to std::logic_error.
Definition: except.hxx:165
pqxx::largeobject_streambuf::overflow
virtual int_type overflow()
Definition: largeobject.hxx:467
pqxx::largeobject_streambuf< char, std::char_traits< char > >::openmode
largeobjectaccess::openmode openmode
Definition: largeobject.hxx:373
pqxx::basic_olostream::traits_type
TRAITS traits_type
Definition: largeobject.hxx:594
pqxx::largeobject_streambuf< char, std::char_traits< char > >::traits_type
std::char_traits< char > traits_type
Definition: largeobject.hxx:369
pqxx::largeobjectaccess::off_type
size_type off_type
Definition: largeobject.hxx:152
pqxx::basic_lostream::off_type
typename traits_type::off_type off_type
Definition: largeobject.hxx:666
pqxx::basic_olostream::pos_type
typename traits_type::pos_type pos_type
Definition: largeobject.hxx:596
pqxx::basic_lostream::basic_lostream
basic_lostream(dbtransaction &t, largeobject o, largeobject::size_type buf_size=512)
Create a basic_lostream.
Definition: largeobject.hxx:674
pqxx::largeobject::to_file
void to_file(dbtransaction &t, std::string_view file) const
Export large object's contents to a local file.
Definition: largeobject.cxx:100
pqxx::largeobject::id
oid id() const noexcept
Object identifier.
Definition: largeobject.hxx:74
pqxx::basic_olostream
Output stream that writes data back to a large object.
Definition: largeobject.hxx:589
pqxx::largeobjectaccess::largeobjectaccess
largeobjectaccess()=delete
pqxx::basic_ilostream::char_type
CHAR char_type
Definition: largeobject.hxx:537
pqxx::transaction_base::conn
connection & conn() const
The connection in which this transaction lives.
Definition: transaction_base.hxx:451
pqxx::largeobject_streambuf::overflow
virtual int_type overflow(int_type ch) override
Definition: largeobject.hxx:425
pqxx::largeobject_streambuf< char, std::char_traits< char > >::int_type
typename traits_type::int_type int_type
Definition: largeobject.hxx:370
pqxx::largeobjectaccess::write
void write(std::string_view buf)
Write string to large object.
Definition: largeobject.hxx:244
pqxx::failure
Run-time failure encountered by libpqxx, similar to std::runtime_error.
Definition: except.hxx:43
pqxx::largeobjectaccess::process_notice
void process_notice(zview) noexcept
Issue message to transaction's notice processor.
Definition: largeobject.cxx:306
pqxx::zview
Marker-type wrapper: zero-terminated std::string_view.
Definition: zview.hxx:38
pqxx::largeobjectaccess::pos_type
size_type pos_type
Definition: largeobject.hxx:153
pqxx::largeobjectaccess::write
void write(char const buf[], std::size_t len)
Write data to large object.
Definition: largeobject.cxx:225
pqxx::basic_ilostream::int_type
typename traits_type::int_type int_type
Definition: largeobject.hxx:539
pqxx::largeobject_streambuf< char, std::char_traits< char > >::off_type
typename traits_type::off_type off_type
Definition: largeobject.hxx:372
pqxx::largeobject_streambuf::largeobject_streambuf
largeobject_streambuf(dbtransaction &t, largeobject o, openmode mode=default_mode, size_type buf_size=512)
Definition: largeobject.hxx:380
pqxx::oid_none
constexpr oid oid_none
The "null" oid.
Definition: util.hxx:211
pqxx::large_object_size_type
int64_t large_object_size_type
Number of bytes in a large object.
Definition: types.hxx:33
pqxx::largeobjectaccess::cseek
pos_type cseek(off_type dest, seekdir dir) noexcept
Seek in large object's data stream.
Definition: largeobject.cxx:198
pqxx::basic_ilostream
Input stream that gets its data from a large object.
Definition: largeobject.hxx:533
pqxx::basic_olostream::basic_olostream
basic_olostream(dbtransaction &t, largeobject o, largeobject::size_type buf_size=512)
Create a basic_olostream.
Definition: largeobject.hxx:605
pqxx::largeobject_streambuf< char, std::char_traits< char > >::char_type
char char_type
Definition: largeobject.hxx:368
pqxx::basic_lostream::traits_type
TRAITS traits_type
Definition: largeobject.hxx:663
pqxx::basic_lostream::int_type
typename traits_type::int_type int_type
Definition: largeobject.hxx:664
pqxx::largeobject_streambuf< char, std::char_traits< char > >::seekdir
largeobjectaccess::seekdir seekdir
Definition: largeobject.hxx:374
pqxx::basic_lostream::char_type
CHAR char_type
Definition: largeobject.hxx:662