libpqxx  7.1.2
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(), buf.size()); }
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 
360 template<typename CHAR = char, typename TRAITS = std::char_traits<CHAR>>
361 class largeobject_streambuf : public std::basic_streambuf<CHAR, TRAITS>
362 {
363  using size_type = largeobject::size_type;
364 
365 public:
366  using char_type = CHAR;
367  using traits_type = TRAITS;
368  using int_type = typename traits_type::int_type;
369  using pos_type = typename traits_type::pos_type;
370  using off_type = typename traits_type::off_type;
373 
375  static constexpr auto default_mode{
376  std::ios::in | std::ios::out | std::ios::binary};
377 
379  dbtransaction &t, largeobject o, openmode mode = default_mode,
380  size_type buf_size = 512) :
381  m_bufsize{buf_size}, m_obj{t, o, mode}, m_g{nullptr}, m_p{nullptr}
382  {
383  initialize(mode);
384  }
385 
387  dbtransaction &t, oid o, openmode mode = default_mode,
388  size_type buf_size = 512) :
389  m_bufsize{buf_size}, m_obj{t, o, mode}, m_g{nullptr}, m_p{nullptr}
390  {
391  initialize(mode);
392  }
393 
394  virtual ~largeobject_streambuf() noexcept
395  {
396  delete[] m_p;
397  delete[] m_g;
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  auto *const pp{this->pptr()};
426  if (pp == nullptr)
427  return eof();
428  auto *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<std::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() = static_cast<char_type>(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  auto *const eb{this->eback()};
458  auto const res{adjust_eof(
459  m_obj.cread(this->eback(), static_cast<std::size_t>(m_bufsize)))};
460  this->setg(
461  eb, eb, eb + (res == eof() ? 0 : static_cast<std::size_t>(res)));
462  return (res == eof() or res == 0) ? eof() : traits_type::to_int_type(*eb);
463  }
464 
465 private:
467  static int_type eof() { return traits_type::eof(); }
468 
470  template<typename INTYPE> static std::streampos adjust_eof(INTYPE pos)
471  {
472  bool const at_eof{pos == -1};
473  if constexpr (std::is_arithmetic_v<std::streampos>)
474  {
475  return check_cast<std::streampos>(
476  (at_eof ? eof() : pos), "large object seek");
477  }
478  else
479  {
480  return std::streampos(at_eof ? eof() : pos);
481  }
482  }
483 
484  void initialize(openmode mode)
485  {
486  if ((mode & std::ios::in) != 0)
487  {
488  m_g = new char_type[unsigned(m_bufsize)];
489  this->setg(m_g, m_g, m_g);
490  }
491  if ((mode & std::ios::out) != 0)
492  {
493  m_p = new char_type[unsigned(m_bufsize)];
494  this->setp(m_p, m_p + m_bufsize);
495  }
496  }
497 
498  size_type const m_bufsize;
499  largeobjectaccess m_obj;
500 
502  char_type *m_g, *m_p;
503 };
504 
505 
507 
515 template<typename CHAR = char, typename TRAITS = std::char_traits<CHAR>>
516 class basic_ilostream : public std::basic_istream<CHAR, TRAITS>
517 {
518  using super = std::basic_istream<CHAR, TRAITS>;
519 
520 public:
521  using char_type = CHAR;
522  using traits_type = TRAITS;
523  using int_type = typename traits_type::int_type;
524  using pos_type = typename traits_type::pos_type;
525  using off_type = typename traits_type::off_type;
526 
528 
534  dbtransaction &t, largeobject o, largeobject::size_type buf_size = 512) :
535  super{nullptr},
536  m_buf{t, o, std::ios::in | std::ios::binary, buf_size}
537  {
538  super::init(&m_buf);
539  }
540 
542 
548  dbtransaction &t, oid o, largeobject::size_type buf_size = 512) :
549  super{nullptr},
550  m_buf{t, o, std::ios::in | std::ios::binary, buf_size}
551  {
552  super::init(&m_buf);
553  }
554 
555 private:
557 };
558 
560 
561 
563 
571 template<typename CHAR = char, typename TRAITS = std::char_traits<CHAR>>
572 class basic_olostream : public std::basic_ostream<CHAR, TRAITS>
573 {
574  using super = std::basic_ostream<CHAR, TRAITS>;
575 
576 public:
577  using char_type = CHAR;
578  using traits_type = TRAITS;
579  using int_type = typename traits_type::int_type;
580  using pos_type = typename traits_type::pos_type;
581  using off_type = typename traits_type::off_type;
582 
584 
590  dbtransaction &t, largeobject o, largeobject::size_type buf_size = 512) :
591  super{nullptr},
592  m_buf{t, o, std::ios::out | std::ios::binary, buf_size}
593  {
594  super::init(&m_buf);
595  }
596 
598 
604  dbtransaction &t, oid o, largeobject::size_type buf_size = 512) :
605  super{nullptr},
606  m_buf{t, o, std::ios::out | std::ios::binary, buf_size}
607  {
608  super::init(&m_buf);
609  }
610 
612  {
613  try
614  {
615  m_buf.pubsync();
616  m_buf.pubsync();
617  }
618  catch (std::exception const &e)
619  {
620  m_buf.process_notice(e.what());
621  }
622  }
623 
624 private:
626 };
627 
629 
630 
632 
640 template<typename CHAR = char, typename TRAITS = std::char_traits<CHAR>>
641 class basic_lostream : public std::basic_iostream<CHAR, TRAITS>
642 {
643  using super = std::basic_iostream<CHAR, TRAITS>;
644 
645 public:
646  using char_type = CHAR;
647  using traits_type = TRAITS;
648  using int_type = typename traits_type::int_type;
649  using pos_type = typename traits_type::pos_type;
650  using off_type = typename traits_type::off_type;
651 
653 
659  dbtransaction &t, largeobject o, largeobject::size_type buf_size = 512) :
660  super{nullptr},
661  m_buf{
662  t, o, std::ios::in | std::ios::out | std::ios::binary, buf_size}
663  {
664  super::init(&m_buf);
665  }
666 
668 
674  dbtransaction &t, oid o, largeobject::size_type buf_size = 512) :
675  super{nullptr},
676  m_buf{
677  t, o, std::ios::in | std::ios::out | std::ios::binary, buf_size}
678  {
679  super::init(&m_buf);
680  }
681 
683  {
684  try
685  {
686  m_buf.pubsync();
687  m_buf.pubsync();
688  }
689  catch (std::exception const &e)
690  {
691  m_buf.process_notice(e.what());
692  }
693  }
694 
695 private:
697 };
698 
700 } // namespace pqxx
701 
702 #include "pqxx/internal/compiler-internal-post.hxx"
703 #endif
typename traits_type::int_type int_type
Definition: largeobject.hxx:648
CHAR char_type
Definition: largeobject.hxx:577
~basic_olostream()
Definition: largeobject.hxx:611
typename traits_type::off_type off_type
Definition: largeobject.hxx:370
TRAITS traits_type
Definition: largeobject.hxx:578
basic_lostream(dbtransaction &t, largeobject o, largeobject::size_type buf_size=512)
Create a basic_lostream.
Definition: largeobject.hxx:658
TRAITS traits_type
Definition: largeobject.hxx:367
TRAITS traits_type
Definition: largeobject.hxx:522
size_type off_type
Definition: largeobject.hxx:152
CHAR char_type
Definition: largeobject.hxx:366
bool operator!=(largeobject const &other) const
Compare object identities.
Definition: largeobject.hxx:92
virtual pos_type seekpos(pos_type pos, openmode) override
Definition: largeobject.hxx:416
int64_t large_object_size_type
Number of bytes in a large object.
Definition: types.hxx:33
basic_olostream(dbtransaction &t, oid o, largeobject::size_type buf_size=512)
Create a basic_olostream.
Definition: largeobject.hxx:603
CHAR char_type
Definition: largeobject.hxx:646
basic_ilostream(dbtransaction &t, oid o, largeobject::size_type buf_size=512)
Create a basic_ilostream.
Definition: largeobject.hxx:547
TO check_cast(FROM value, char const description[])
Cast a numeric value to another type, or throw if it underflows/overflows.
Definition: util.hxx:52
virtual int_type overflow(int_type ch) override
Definition: largeobject.hxx:423
largeobjectaccess::seekdir seekdir
Definition: largeobject.hxx:372
typename traits_type::pos_type pos_type
Definition: largeobject.hxx:524
Input stream that gets its data from a large object.
Definition: largeobject.hxx:516
bool operator==(largeobject const &other) const
Compare object identities.
Definition: largeobject.hxx:86
~largeobjectaccess() noexcept
Definition: largeobject.hxx:209
largeobject_streambuf(dbtransaction &t, largeobject o, openmode mode=default_mode, size_type buf_size=512)
Definition: largeobject.hxx:378
void write(std::string_view buf)
Write string to large object.
Definition: largeobject.hxx:244
typename traits_type::int_type int_type
Definition: largeobject.hxx:579
typename traits_type::int_type int_type
Definition: largeobject.hxx:368
The home of all libpqxx classes, functions, templates, etc.
Definition: array.hxx:25
Connection to a database.
Definition: connection.hxx:136
virtual int_type overflow()
Definition: largeobject.hxx:451
constexpr oid oid_none
The "null" oid.
Definition: util.hxx:187
basic_olostream(dbtransaction &t, largeobject o, largeobject::size_type buf_size=512)
Create a basic_olostream.
Definition: largeobject.hxx:589
size_type pos_type
Definition: largeobject.hxx:153
Abstract transaction base class: bracket transactions on the database.
Definition: dbtransaction.hxx:52
virtual int sync() override
Definition: largeobject.hxx:404
Identity of a large object.
Definition: largeobject.hxx:34
typename traits_type::pos_type pos_type
Definition: largeobject.hxx:649
bool operator>(largeobject const &other) const
Compare object identities.
Definition: largeobject.hxx:116
static PQXX_PURE internal::pq::PGconn * raw_connection(dbtransaction const &T)
Definition: largeobject.cxx:133
typename traits_type::off_type off_type
Definition: largeobject.hxx:525
virtual int_type underflow() override
Definition: largeobject.hxx:453
typename traits_type::off_type off_type
Definition: largeobject.hxx:650
largeobjectaccess::openmode openmode
Definition: largeobject.hxx:371
bool operator<(largeobject const &other) const
Compare object identities.
Definition: largeobject.hxx:110
typename traits_type::pos_type pos_type
Definition: largeobject.hxx:369
Stream that reads and writes a large object.
Definition: largeobject.hxx:641
Streambuf to use large objects in standard I/O streams.
Definition: largeobject.hxx:361
basic_ilostream(dbtransaction &t, largeobject o, largeobject::size_type buf_size=512)
Create a basic_ilostream.
Definition: largeobject.hxx:533
~basic_lostream()
Definition: largeobject.hxx:682
virtual ~largeobject_streambuf() noexcept
Definition: largeobject.hxx:394
void remove(dbtransaction &t) const
Delete large object from database.
Definition: largeobject.cxx:116
typename traits_type::off_type off_type
Definition: largeobject.hxx:581
basic_lostream(dbtransaction &t, oid o, largeobject::size_type buf_size=512)
Create a basic_lostream.
Definition: largeobject.hxx:673
Output stream that writes data back to a large object.
Definition: largeobject.hxx:572
largeobject_streambuf(dbtransaction &t, oid o, openmode mode=default_mode, size_type buf_size=512)
Definition: largeobject.hxx:386
Accessor for large object&#39;s contents.
Definition: largeobject.hxx:148
large_object_size_type size_type
Definition: largeobject.hxx:37
std::ios::seekdir seekdir
Seek direction: beg, cur, end.
Definition: largeobject.hxx:170
typename traits_type::int_type int_type
Definition: largeobject.hxx:523
oid id() const noexcept
Object identifier.
Definition: largeobject.hxx:74
std::ios::openmode openmode
Open mode: in, out (can be combined using "bitwise or").
Definition: largeobject.hxx:163
TRAITS traits_type
Definition: largeobject.hxx:647
void to_file(dbtransaction &t, std::string_view file) const
Export large object&#39;s contents to a local file.
Definition: largeobject.cxx:98
virtual pos_type seekoff(off_type offset, seekdir dir, openmode) override
Definition: largeobject.hxx:411
void process_notice(std::string const &s)
For use by large object stream classes.
Definition: largeobject.hxx:401
bool operator>=(largeobject const &other) const
Compare object identities.
Definition: largeobject.hxx:104
typename traits_type::pos_type pos_type
Definition: largeobject.hxx:580
CHAR char_type
Definition: largeobject.hxx:521
bool operator<=(largeobject const &other) const
Compare object identities.
Definition: largeobject.hxx:98
void to_file(std::string_view file) const
Export large object&#39;s contents to a local file.
Definition: largeobject.hxx:221
large_object_size_type size_type
Definition: largeobject.hxx:37