libpqxx  7.0.5
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{std::ios::in | std::ios::out |
167  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[], 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[], 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[], size_t len) noexcept;
299 
301 
307  off_type cread(char buf[], 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{std::ios::in | std::ios::out |
376  std::ios::binary};
377 
379  dbtransaction &t, largeobject o, openmode mode = default_mode,
380  size_type buf_size = 512) :
381  m_bufsize{buf_size},
382  m_obj{t, o, mode},
383  m_g{nullptr},
384  m_p{nullptr}
385  {
386  initialize(mode);
387  }
388 
390  dbtransaction &t, oid o, openmode mode = default_mode,
391  size_type buf_size = 512) :
392  m_bufsize{buf_size},
393  m_obj{t, o, mode},
394  m_g{nullptr},
395  m_p{nullptr}
396  {
397  initialize(mode);
398  }
399 
400  virtual ~largeobject_streambuf() noexcept
401  {
402  delete[] m_p;
403  delete[] m_g;
404  }
405 
407  void process_notice(std::string const &s) { m_obj.process_notice(s); }
408 
409 protected:
410  virtual int sync() override
411  {
412  // setg() sets eback, gptr, egptr.
413  this->setg(this->eback(), this->eback(), this->egptr());
414  return overflow(eof());
415  }
416 
417  virtual pos_type seekoff(off_type offset, seekdir dir, openmode) override
418  {
419  return adjust_eof(m_obj.cseek(largeobjectaccess::off_type(offset), dir));
420  }
421 
422  virtual pos_type seekpos(pos_type pos, openmode) override
423  {
424  largeobjectaccess::pos_type const newpos{
425  m_obj.cseek(largeobjectaccess::off_type(pos), std::ios::beg)};
426  return adjust_eof(newpos);
427  }
428 
429  virtual int_type overflow(int_type ch) override
430  {
431  auto *const pp{this->pptr()};
432  if (pp == nullptr)
433  return eof();
434  auto *const pb{this->pbase()};
435  int_type res{0};
436 
437  if (pp > pb)
438  {
439  auto const out{
440  adjust_eof(m_obj.cwrite(pb, static_cast<std::size_t>(pp - pb)))};
441  if constexpr (std::is_arithmetic_v<decltype(out)>)
442  res = check_cast<int_type>(out);
443  else
444  res = int_type(out);
445  }
446  this->setp(m_p, m_p + m_bufsize);
447 
448  // Write that one more character, if it's there.
449  if (ch != eof())
450  {
451  *this->pptr() = static_cast<char_type>(ch);
452  this->pbump(1);
453  }
454  return res;
455  }
456 
457  virtual int_type overflow() { return overflow(eof()); }
458 
459  virtual int_type underflow() override
460  {
461  if (this->gptr() == nullptr)
462  return eof();
463  auto *const eb{this->eback()};
464  auto const res{adjust_eof(
465  m_obj.cread(this->eback(), static_cast<std::size_t>(m_bufsize)))};
466  this->setg(
467  eb, eb, eb + (res == eof() ? 0 : static_cast<std::size_t>(res)));
468  return (res == eof() or res == 0) ? eof() : traits_type::to_int_type(*eb);
469  }
470 
471 private:
473  static int_type eof() { return traits_type::eof(); }
474 
476  template<typename INTYPE> static std::streampos adjust_eof(INTYPE pos)
477  {
478  bool const at_eof{pos == -1};
479  if constexpr (std::is_arithmetic_v<std::streampos>)
480  {
481  return check_cast<std::streampos>(
482  (at_eof ? eof() : pos), "large object seek");
483  }
484  else
485  {
486  return std::streampos(at_eof ? eof() : pos);
487  }
488  }
489 
490  void initialize(openmode mode)
491  {
492  if ((mode & std::ios::in) != 0)
493  {
494  m_g = new char_type[unsigned(m_bufsize)];
495  this->setg(m_g, m_g, m_g);
496  }
497  if ((mode & std::ios::out) != 0)
498  {
499  m_p = new char_type[unsigned(m_bufsize)];
500  this->setp(m_p, m_p + m_bufsize);
501  }
502  }
503 
504  size_type const m_bufsize;
505  largeobjectaccess m_obj;
506 
508  char_type *m_g, *m_p;
509 };
510 
511 
513 
521 template<typename CHAR = char, typename TRAITS = std::char_traits<CHAR>>
522 class basic_ilostream : public std::basic_istream<CHAR, TRAITS>
523 {
524  using super = std::basic_istream<CHAR, TRAITS>;
525 
526 public:
527  using char_type = CHAR;
528  using traits_type = TRAITS;
529  using int_type = typename traits_type::int_type;
530  using pos_type = typename traits_type::pos_type;
531  using off_type = typename traits_type::off_type;
532 
534 
540  dbtransaction &t, largeobject o, largeobject::size_type buf_size = 512) :
541  super{nullptr},
542  m_buf{t, o, std::ios::in | std::ios::binary, buf_size}
543  {
544  super::init(&m_buf);
545  }
546 
548 
554  dbtransaction &t, oid o, largeobject::size_type buf_size = 512) :
555  super{nullptr},
556  m_buf{t, o, std::ios::in | std::ios::binary, buf_size}
557  {
558  super::init(&m_buf);
559  }
560 
561 private:
563 };
564 
566 
567 
569 
577 template<typename CHAR = char, typename TRAITS = std::char_traits<CHAR>>
578 class basic_olostream : public std::basic_ostream<CHAR, TRAITS>
579 {
580  using super = std::basic_ostream<CHAR, TRAITS>;
581 
582 public:
583  using char_type = CHAR;
584  using traits_type = TRAITS;
585  using int_type = typename traits_type::int_type;
586  using pos_type = typename traits_type::pos_type;
587  using off_type = typename traits_type::off_type;
588 
590 
596  dbtransaction &t, largeobject o, largeobject::size_type buf_size = 512) :
597  super{nullptr},
598  m_buf{t, o, std::ios::out | std::ios::binary, buf_size}
599  {
600  super::init(&m_buf);
601  }
602 
604 
610  dbtransaction &t, oid o, largeobject::size_type buf_size = 512) :
611  super{nullptr},
612  m_buf{t, o, std::ios::out | std::ios::binary, buf_size}
613  {
614  super::init(&m_buf);
615  }
616 
618  {
619  try
620  {
621  m_buf.pubsync();
622  m_buf.pubsync();
623  }
624  catch (std::exception const &e)
625  {
626  m_buf.process_notice(e.what());
627  }
628  }
629 
630 private:
632 };
633 
635 
636 
638 
646 template<typename CHAR = char, typename TRAITS = std::char_traits<CHAR>>
647 class basic_lostream : public std::basic_iostream<CHAR, TRAITS>
648 {
649  using super = std::basic_iostream<CHAR, TRAITS>;
650 
651 public:
652  using char_type = CHAR;
653  using traits_type = TRAITS;
654  using int_type = typename traits_type::int_type;
655  using pos_type = typename traits_type::pos_type;
656  using off_type = typename traits_type::off_type;
657 
659 
665  dbtransaction &t, largeobject o, largeobject::size_type buf_size = 512) :
666  super{nullptr},
667  m_buf{t, o, std::ios::in | std::ios::out | std::ios::binary,
668  buf_size}
669  {
670  super::init(&m_buf);
671  }
672 
674 
680  dbtransaction &t, oid o, largeobject::size_type buf_size = 512) :
681  super{nullptr},
682  m_buf{t, o, std::ios::in | std::ios::out | std::ios::binary,
683  buf_size}
684  {
685  super::init(&m_buf);
686  }
687 
689  {
690  try
691  {
692  m_buf.pubsync();
693  m_buf.pubsync();
694  }
695  catch (std::exception const &e)
696  {
697  m_buf.process_notice(e.what());
698  }
699  }
700 
701 private:
703 };
704 
706 } // namespace pqxx
707 
708 #include "pqxx/internal/compiler-internal-post.hxx"
709 #endif
typename traits_type::int_type int_type
Definition: largeobject.hxx:654
CHAR char_type
Definition: largeobject.hxx:583
~basic_olostream()
Definition: largeobject.hxx:617
typename traits_type::off_type off_type
Definition: largeobject.hxx:370
TRAITS traits_type
Definition: largeobject.hxx:584
basic_lostream(dbtransaction &t, largeobject o, largeobject::size_type buf_size=512)
Create a basic_lostream.
Definition: largeobject.hxx:664
TRAITS traits_type
Definition: largeobject.hxx:367
TRAITS traits_type
Definition: largeobject.hxx:528
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:422
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:609
CHAR char_type
Definition: largeobject.hxx:652
basic_ilostream(dbtransaction &t, oid o, largeobject::size_type buf_size=512)
Create a basic_ilostream.
Definition: largeobject.hxx:553
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:429
largeobjectaccess::seekdir seekdir
Definition: largeobject.hxx:372
typename traits_type::pos_type pos_type
Definition: largeobject.hxx:530
Input stream that gets its data from a large object.
Definition: largeobject.hxx:522
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:585
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:135
virtual int_type overflow()
Definition: largeobject.hxx:457
constexpr oid oid_none
The "null" oid.
Definition: util.hxx:180
basic_olostream(dbtransaction &t, largeobject o, largeobject::size_type buf_size=512)
Create a basic_olostream.
Definition: largeobject.hxx:595
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:410
Identity of a large object.
Definition: largeobject.hxx:34
typename traits_type::pos_type pos_type
Definition: largeobject.hxx:655
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:127
typename traits_type::off_type off_type
Definition: largeobject.hxx:531
virtual int_type underflow() override
Definition: largeobject.hxx:459
typename traits_type::off_type off_type
Definition: largeobject.hxx:656
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:647
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:539
~basic_lostream()
Definition: largeobject.hxx:688
virtual ~largeobject_streambuf() noexcept
Definition: largeobject.hxx:400
void remove(dbtransaction &t) const
Delete large object from database.
Definition: largeobject.cxx:113
typename traits_type::off_type off_type
Definition: largeobject.hxx:587
basic_lostream(dbtransaction &t, oid o, largeobject::size_type buf_size=512)
Create a basic_lostream.
Definition: largeobject.hxx:679
Output stream that writes data back to a large object.
Definition: largeobject.hxx:578
largeobject_streambuf(dbtransaction &t, oid o, openmode mode=default_mode, size_type buf_size=512)
Definition: largeobject.hxx:389
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:529
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:653
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:417
void process_notice(std::string const &s)
For use by large object stream classes.
Definition: largeobject.hxx:407
bool operator>=(largeobject const &other) const
Compare object identities.
Definition: largeobject.hxx:104
typename traits_type::pos_type pos_type
Definition: largeobject.hxx:586
CHAR char_type
Definition: largeobject.hxx:527
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