libpqxx
The C++ client library for PostgreSQL
largeobject.hxx
Go to the documentation of this file.
1 /* Large Objects interface. Deprecated; use blob instead.
2  *
3  * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/largeobject instead.
4  *
5  * Copyright (c) 2000-2026, Jeroen T. Vermeulen.
6  *
7  * See COPYING for copyright license. If you did not receive a file called
8  * COPYING with this source code, please notify the distributor of this
9  * mistake, or contact the author.
10  */
11 #ifndef PQXX_LARGEOBJECT_HXX
12 #define PQXX_LARGEOBJECT_HXX
13 
14 #if !defined(PQXX_HEADER_PRE)
15 # error "Include libpqxx headers as <pqxx/header>, not <pqxx/header.hxx>."
16 #endif
17 
18 #include <streambuf>
19 
20 #include "pqxx/dbtransaction.hxx"
21 
22 
23 // This whole header is deprecated, so there's not much point checking these.
24 //
25 // NOLINTBEGIN(
26 // cppcoreguidelines-avoid-const-or-ref-data-members,
27 // fuchsia-multiple-inheritance
28 // )
29 
30 namespace pqxx
31 {
32 // This class is deprecated.
33 // LCOV_EXCL_START
34 
36 
44 {
45 public:
47 
50  [[deprecated("Use blob instead.")]] largeobject() noexcept = default;
51 
53 
55  [[deprecated("Use blob instead.")]] explicit largeobject(dbtransaction &t);
56 
58 
62  [[deprecated("Use blob instead.")]] explicit largeobject(oid o) noexcept :
63  m_id{o}
64  {}
65 
67 
71  [[deprecated("Use blob instead.")]] largeobject(
72  dbtransaction &t, std::string_view file);
73 
74  // NOLINTBEGIN(google-explicit-constructor,hicpp-explicit-conversions)
76 
80  [[deprecated("Use blob instead.")]] largeobject(
81  largeobjectaccess const &o) noexcept;
82  // NOLINTEND(google-explicit-constructor,hicpp-explicit-conversions)
83 
85 
89  [[nodiscard]] oid id() const noexcept { return m_id; }
90 
100 
101  [[nodiscard]] bool operator==(largeobject const &other) const
102  {
103  return m_id == other.m_id;
104  }
106 
107  [[nodiscard]] bool operator!=(largeobject const &other) const
108  {
109  return m_id != other.m_id;
110  }
112 
113  [[nodiscard]] bool operator<=(largeobject const &other) const
114  {
115  return m_id <= other.m_id;
116  }
118 
119  [[nodiscard]] bool operator>=(largeobject const &other) const
120  {
121  return m_id >= other.m_id;
122  }
124 
125  [[nodiscard]] bool operator<(largeobject const &other) const
126  {
127  return m_id < other.m_id;
128  }
130 
131  [[nodiscard]] bool operator>(largeobject const &other) const
132  {
133  return m_id > other.m_id;
134  }
136 
138 
142  void to_file(dbtransaction &t, std::string_view file) const;
143 
145 
149  void remove(dbtransaction &t) const;
150 
151 protected:
152  PQXX_PURE [[nodiscard]] static internal::pq::PGconn *
153  raw_connection(dbtransaction const &T);
154 
155  PQXX_PRIVATE [[nodiscard]] std::string
156  reason(connection const &, int err) const;
157 
158 private:
159  oid m_id = oid_none;
160 };
161 
162 
164 
167 {
168 public:
172 
174 
181  using openmode = std::ios::openmode;
182 
184  static constexpr auto default_mode{
185  std::ios::in | std::ios::out | std::ios::binary};
186 
188  using seekdir = std::ios::seekdir;
189 
191 
196  [[deprecated("Use blob instead.")]] explicit largeobjectaccess(
197  dbtransaction &t, openmode mode = default_mode);
198 
200 
207  [[deprecated("Use blob instead.")]] largeobjectaccess(
208  dbtransaction &t, oid o, openmode mode = default_mode);
209 
211 
217  [[deprecated("Use blob instead.")]] largeobjectaccess(
218  dbtransaction &t, largeobject o, openmode mode = default_mode);
219 
221 
226  [[deprecated("Use blob instead.")]] largeobjectaccess(
227  dbtransaction &t, std::string_view file, openmode mode = default_mode);
228 
229  largeobjectaccess() = delete;
232  ~largeobjectaccess() noexcept { close(); }
233 
236 
238 
241  using largeobject::id;
242 
244 
247  void to_file(std::string_view file) const
248  {
249  largeobject::to_file(m_trans, file);
250  }
251 
252  using largeobject::to_file;
253 
259 
264  void write(char const buf[], std::size_t len);
265 
267 
270  void write(std::string_view buf) { write(std::data(buf), std::size(buf)); }
271 
273 
279  size_type read(char buf[], std::size_t len);
280 
282 
285  size_type seek(size_type dest, seekdir dir);
286 
288 
291  [[nodiscard]] size_type tell() const;
293 
307 
315  pos_type cseek(off_type dest, seekdir dir) noexcept;
316 
318 
324  off_type cwrite(char const buf[], std::size_t len) noexcept;
325 
327 
333  off_type cread(char buf[], std::size_t len) noexcept;
334 
336 
340  [[nodiscard]] pos_type ctell() const noexcept;
342 
348  void process_notice(zview) noexcept;
350 
351  using largeobject::remove;
352 
353  using largeobject::operator==;
354  using largeobject::operator!=;
355  using largeobject::operator<;
356  using largeobject::operator<=;
357  using largeobject::operator>;
358  using largeobject::operator>=;
359 
360 private:
361  PQXX_PRIVATE [[nodiscard]] std::string reason(int err) const;
362  [[nodiscard]] internal::pq::PGconn *raw_connection() const
363  {
364  return largeobject::raw_connection(m_trans);
365  }
366 
367  PQXX_PRIVATE void open(openmode mode);
368  void close() noexcept;
369 
370  dbtransaction &m_trans;
371  int m_fd = -1;
372 };
373 
374 
375 // NOLINTBEGIN(cppcoreguidelines-owning-memory)
376 
378 
389 template<typename CHAR = char, typename TRAITS = std::char_traits<CHAR>>
390 class largeobject_streambuf final : public std::basic_streambuf<CHAR, TRAITS>
391 {
392  using size_type = largeobject::size_type;
393 
394 public:
395  using char_type = CHAR;
396  using traits_type = TRAITS;
397  using int_type = typename traits_type::int_type;
398  using pos_type = typename traits_type::pos_type;
399  using off_type = typename traits_type::off_type;
402 
404  static constexpr auto default_mode{
405  std::ios::in | std::ios::out | std::ios::binary};
406 
408  [[deprecated("Use blob instead.")]] largeobject_streambuf(
409  dbtransaction &t, largeobject o, openmode mode = default_mode,
410  size_type buf_size = 512) :
411  m_bufsize{buf_size}, m_obj{t, o, mode}, m_g{nullptr}, m_p{nullptr}
412  {
413  initialize(mode);
414  }
416 
417  [[deprecated("Use blob instead.")]] largeobject_streambuf(
418  dbtransaction &t, oid o, openmode mode = default_mode,
419  size_type buf_size = 512) :
420  m_bufsize{buf_size}, m_obj{t, o, mode}, m_g{nullptr}, m_p{nullptr}
421  {
422  initialize(mode);
423  }
424 
427 
428  ~largeobject_streambuf() noexcept override
429  {
430  delete[] m_p;
431  delete[] m_g;
432  }
433 
436 
438  void process_notice(zview const &s) { m_obj.process_notice(s); }
439 
440 protected:
441  int sync() override
442  {
443  // setg() sets eback, gptr, egptr.
444  this->setg(this->eback(), this->eback(), this->egptr());
445  return overflow(eof());
446  }
447 
448  pos_type seekoff(off_type offset, seekdir dir, openmode) override
449  {
450  return adjust_eof(m_obj.cseek(largeobjectaccess::off_type(offset), dir));
451  }
452 
454  {
455  largeobjectaccess::pos_type const newpos{
456  m_obj.cseek(largeobjectaccess::off_type(pos), std::ios::beg)};
457  return adjust_eof(newpos);
458  }
459 
460  int_type overflow(int_type ch = eof()) override
461  {
462  auto *const pp{this->pptr()};
463  if (pp == nullptr)
464  return eof();
465  auto *const pb{this->pbase()};
466  int_type res{0};
467 
468  if (pp > pb)
469  {
470  auto const write_sz{pp - pb};
471  auto const written_sz{
472  m_obj.cwrite(pb, static_cast<std::size_t>(pp - pb))};
473  if (std::cmp_less_equal(written_sz, 0))
474  throw internal_error{
475  "pqxx::largeobject: write failed "
476  "(is transaction still valid on write or flush?), "
477  "libpq reports error"};
478  else if (write_sz != written_sz)
480  "pqxx::largeobject: write failed "
481  "(is transaction still valid on write or flush?), {}/{} "
482  "bytes written",
483  written_sz, write_sz)};
484  auto const out{adjust_eof(written_sz)};
485 
486  if constexpr (std::is_arithmetic_v<decltype(out)>)
487  res = check_cast<int_type>(out, "largeobject position"sv);
488  else
489  res = int_type(out);
490  }
491  this->setp(m_p, m_p + m_bufsize);
492 
493  // Write that one more character, if it's there.
494  if (ch != eof())
495  {
496  *this->pptr() = static_cast<char_type>(ch);
497  this->pbump(1);
498  }
499  return res;
500  }
501 
502  int_type underflow() override
503  {
504  if (this->gptr() == nullptr)
505  return eof();
506  auto *const eb{this->eback()};
507  auto const res{adjust_eof(
508  m_obj.cread(this->eback(), static_cast<std::size_t>(m_bufsize)))};
509  this->setg(
510  eb, eb, eb + (res == eof() ? 0 : static_cast<std::size_t>(res)));
511  return (res == eof() or res == 0) ? eof() : traits_type::to_int_type(*eb);
512  }
513 
514 private:
516  static constexpr int_type eof() { return traits_type::eof(); }
517 
519  template<typename INTYPE> static std::streampos adjust_eof(INTYPE pos)
520  {
521  bool const at_eof{pos == -1};
522  if constexpr (std::is_arithmetic_v<std::streampos>)
523  {
524  return check_cast<std::streampos>(
525  (at_eof ? eof() : pos), "large object seek"sv);
526  }
527  else
528  {
529  return std::streampos(at_eof ? eof() : pos);
530  }
531  }
532 
533  void initialize(openmode mode)
534  {
535  if ((mode & std::ios::in) != 0)
536  {
537  m_g = new char_type[unsigned(m_bufsize)];
538  this->setg(m_g, m_g, m_g);
539  }
540  if ((mode & std::ios::out) != 0)
541  {
542  m_p = new char_type[unsigned(m_bufsize)];
543  this->setp(m_p, m_p + m_bufsize);
544  }
545  }
546 
547  size_type const m_bufsize;
548  largeobjectaccess m_obj;
549 
551  char_type *m_g, *m_p;
552 };
553 
554 // NOLINTEND(cppcoreguidelines-owning-memory)
555 
557 
566 template<typename CHAR = char, typename TRAITS = std::char_traits<CHAR>>
567 class basic_ilostream final : public std::basic_istream<CHAR, TRAITS>
568 {
569  using super = std::basic_istream<CHAR, TRAITS>;
570 
571 public:
572  using char_type = CHAR;
573  using traits_type = TRAITS;
574  using int_type = typename traits_type::int_type;
575  using pos_type = typename traits_type::pos_type;
576  using off_type = typename traits_type::off_type;
577 
580 
585  [[deprecated("Use blob instead.")]] basic_ilostream(
586  dbtransaction &t, largeobject o, largeobject::size_type buf_size = 512) :
587  super{nullptr},
588  m_buf{t, o, std::ios::in | std::ios::binary, buf_size}
589  {
590  super::init(&m_buf);
591  }
593 
595 
600  [[deprecated("Use blob instead.")]] basic_ilostream(
601  dbtransaction &t, oid o, largeobject::size_type buf_size = 512) :
602  super{nullptr},
603  m_buf{t, o, std::ios::in | std::ios::binary, buf_size}
604  {
605  super::init(&m_buf);
606  }
607 
608 private:
610 };
611 
613 
614 
616 
624 template<typename CHAR = char, typename TRAITS = std::char_traits<CHAR>>
625 class basic_olostream final : public std::basic_ostream<CHAR, TRAITS>
626 {
627  using super = std::basic_ostream<CHAR, TRAITS>;
628 
629 public:
630  using char_type = CHAR;
631  using traits_type = TRAITS;
632  using int_type = typename traits_type::int_type;
633  using pos_type = typename traits_type::pos_type;
634  using off_type = typename traits_type::off_type;
635 
638 
643  [[deprecated("Use blob instead.")]] basic_olostream(
644  dbtransaction &t, largeobject o, largeobject::size_type buf_size = 512) :
645  super{nullptr},
646  m_buf{t, o, std::ios::out | std::ios::binary, buf_size}
647  {
648  super::init(&m_buf);
649  }
651 
653 
658  [[deprecated("Use blob instead.")]] basic_olostream(
659  dbtransaction &t, oid o, largeobject::size_type buf_size = 512) :
660  super{nullptr},
661  m_buf{t, o, std::ios::out | std::ios::binary, buf_size}
662  {
663  super::init(&m_buf);
664  }
665 
666  basic_olostream(basic_olostream const &) = delete;
668 
669  ~basic_olostream() override
670  {
671  try
672  {
673  m_buf.pubsync();
674  m_buf.pubsync();
675  }
676  catch (std::exception const &e)
677  {
678  m_buf.process_notice(e.what());
679  }
680  }
681 
684 
685 private:
687 };
688 
690 
691 
693 
702 template<typename CHAR = char, typename TRAITS = std::char_traits<CHAR>>
703 class basic_lostream final : public std::basic_iostream<CHAR, TRAITS>
704 {
705  using super = std::basic_iostream<CHAR, TRAITS>;
706 
707 public:
708  using char_type = CHAR;
709  using traits_type = TRAITS;
710  using int_type = typename traits_type::int_type;
711  using pos_type = typename traits_type::pos_type;
712  using off_type = typename traits_type::off_type;
713 
715 
720  [[deprecated("Use blob instead.")]] basic_lostream(
721  dbtransaction &t, largeobject o, largeobject::size_type buf_size = 512) :
722  super{nullptr},
723  m_buf{
724  t, o, std::ios::in | std::ios::out | std::ios::binary, buf_size}
725  {
726  super::init(&m_buf);
727  }
728 
730 
735  [[deprecated("Use blob instead.")]] basic_lostream(
736  dbtransaction &t, oid o, largeobject::size_type buf_size = 512) :
737  super{nullptr},
738  m_buf{
739  t, o, std::ios::in | std::ios::out | std::ios::binary, buf_size}
740  {
741  super::init(&m_buf);
742  }
743 
744  basic_lostream() = delete;
745  basic_lostream(basic_lostream const &) = delete;
747 
748  ~basic_lostream() override
749  {
750  try
751  {
752  m_buf.pubsync();
753  m_buf.pubsync();
754  }
755  catch (std::exception const &e)
756  {
757  m_buf.process_notice(e.what());
758  }
759  }
760 
763 
764 private:
766 };
767 
769 
770 // LCOV_EXCL_STOP
771 } // namespace pqxx
772 
773 // NOLINTEND(
774 // cppcoreguidelines-avoid-const-or-ref-data-members,
775 // fuchsia-multiple-inheritance
776 // )
777 #endif
Input stream that gets its data from a large object.
Definition: largeobject.hxx:568
basic_ilostream(dbtransaction &t, oid o, largeobject::size_type buf_size=512)
Create a basic_ilostream.
Definition: largeobject.hxx:600
CHAR char_type
Definition: largeobject.hxx:572
basic_ilostream(dbtransaction &t, largeobject o, largeobject::size_type buf_size=512)
Create a basic_ilostream.
Definition: largeobject.hxx:585
typename traits_type::int_type int_type
Definition: largeobject.hxx:574
TRAITS traits_type
Definition: largeobject.hxx:573
typename traits_type::off_type off_type
Definition: largeobject.hxx:576
typename traits_type::pos_type pos_type
Definition: largeobject.hxx:575
Stream that reads and writes a large object.
Definition: largeobject.hxx:704
typename traits_type::pos_type pos_type
Definition: largeobject.hxx:711
typename traits_type::int_type int_type
Definition: largeobject.hxx:710
basic_lostream & operator=(basic_lostream &&)=delete
typename traits_type::off_type off_type
Definition: largeobject.hxx:712
basic_lostream(dbtransaction &t, largeobject o, largeobject::size_type buf_size=512)
Create a basic_lostream.
Definition: largeobject.hxx:720
~basic_lostream() override
Definition: largeobject.hxx:748
basic_lostream(dbtransaction &t, oid o, largeobject::size_type buf_size=512)
Create a basic_lostream.
Definition: largeobject.hxx:735
TRAITS traits_type
Definition: largeobject.hxx:709
basic_lostream(basic_lostream const &)=delete
basic_lostream(basic_lostream &&)=delete
CHAR char_type
Definition: largeobject.hxx:708
basic_lostream & operator=(basic_lostream const &)=delete
Output stream that writes data back to a large object.
Definition: largeobject.hxx:626
typename traits_type::off_type off_type
Definition: largeobject.hxx:634
typename traits_type::pos_type pos_type
Definition: largeobject.hxx:633
basic_olostream(basic_olostream &&)=delete
basic_olostream(dbtransaction &t, largeobject o, largeobject::size_type buf_size=512)
Create a basic_olostream.
Definition: largeobject.hxx:643
typename traits_type::int_type int_type
Definition: largeobject.hxx:632
CHAR char_type
Definition: largeobject.hxx:630
basic_olostream & operator=(basic_olostream const &)=delete
~basic_olostream() override
Definition: largeobject.hxx:669
basic_olostream(dbtransaction &t, oid o, largeobject::size_type buf_size=512)
Create a basic_olostream.
Definition: largeobject.hxx:658
TRAITS traits_type
Definition: largeobject.hxx:631
basic_olostream(basic_olostream const &)=delete
basic_olostream & operator=(basic_olostream &&)=delete
Definition: blob.hxx:44
Connection to a database.
Definition: connection.hxx:273
Streambuf to use large objects in standard I/O streams.
Definition: largeobject.hxx:391
largeobject_streambuf(largeobject_streambuf const &)=delete
TRAITS traits_type
Definition: largeobject.hxx:396
typename traits_type::int_type int_type
Definition: largeobject.hxx:397
int_type underflow() override
Definition: largeobject.hxx:502
largeobject_streambuf(dbtransaction &t, oid o, openmode mode=default_mode, size_type buf_size=512)
Definition: largeobject.hxx:417
CHAR char_type
Definition: largeobject.hxx:395
typename traits_type::off_type off_type
Definition: largeobject.hxx:399
void process_notice(zview const &s)
For use by large object stream classes.
Definition: largeobject.hxx:438
largeobject_streambuf & operator=(largeobject_streambuf &&)=delete
largeobjectaccess::seekdir seekdir
Definition: largeobject.hxx:401
largeobject_streambuf(largeobject_streambuf &&)=delete
largeobjectaccess::openmode openmode
Definition: largeobject.hxx:400
int_type overflow(int_type ch=eof()) override
Definition: largeobject.hxx:460
typename traits_type::pos_type pos_type
Definition: largeobject.hxx:398
largeobject_streambuf & operator=(largeobject_streambuf const &)=delete
~largeobject_streambuf() noexcept override
Definition: largeobject.hxx:428
pos_type seekpos(pos_type pos, openmode) override
Definition: largeobject.hxx:453
largeobject_streambuf(dbtransaction &t, largeobject o, openmode mode=default_mode, size_type buf_size=512)
Definition: largeobject.hxx:408
pos_type seekoff(off_type offset, seekdir dir, openmode) override
Definition: largeobject.hxx:448
int sync() override
Definition: largeobject.hxx:441
Identity of a large object.
Definition: largeobject.hxx:44
bool operator==(largeobject const &other) const
Compare object identities.
Definition: largeobject.hxx:101
static PQXX_PURE internal::pq::PGconn * raw_connection(dbtransaction const &T)
Definition: largeobject.cxx:160
bool operator>=(largeobject const &other) const
Compare object identities.
Definition: largeobject.hxx:119
bool operator<=(largeobject const &other) const
Compare object identities.
Definition: largeobject.hxx:113
void to_file(dbtransaction &t, std::string_view file) const
Export large object's contents to a local file.
Definition: largeobject.cxx:128
large_object_size_type size_type
Definition: largeobject.hxx:46
bool operator<(largeobject const &other) const
Compare object identities.
Definition: largeobject.hxx:125
largeobject() noexcept=default
bool operator!=(largeobject const &other) const
Compare object identities.
Definition: largeobject.hxx:107
bool operator>(largeobject const &other) const
Compare object identities.
Definition: largeobject.hxx:131
oid id() const noexcept
Object identifier.
Definition: largeobject.hxx:89
Accessor for large object's contents.
Definition: largeobject.hxx:167
size_type pos_type
Definition: largeobject.hxx:171
largeobjectaccess & operator=(largeobjectaccess const &)=delete
std::ios::openmode openmode
Open mode: in, out (can be combined using "bitwise or").
Definition: largeobject.hxx:181
std::ios::seekdir seekdir
Seek direction: beg, cur, end.
Definition: largeobject.hxx:188
largeobjectaccess(largeobjectaccess &&)=delete
largeobjectaccess(largeobjectaccess const &)=delete
void to_file(std::string_view file) const
Export large object's contents to a local file.
Definition: largeobject.hxx:247
~largeobjectaccess() noexcept
Definition: largeobject.hxx:232
void write(std::string_view buf)
Write string to large object.
Definition: largeobject.hxx:270
size_type off_type
Definition: largeobject.hxx:170
largeobjectaccess & operator=(largeobjectaccess &&)=delete
Marker-type wrapper: zero-terminated std::string_view.
Definition: zview.hxx:55
Internal error in libpqxx library.
Definition: except.hxx:558
Abstract transaction base class: bracket transactions on the database.
Definition: dbtransaction.hxx:54
#define PQXX_LIBEXPORT
Definition: header-pre.hxx:206
#define PQXX_PURE
Definition: header-pre.hxx:64
#define PQXX_PRIVATE
Definition: header-pre.hxx:207
void PGconn
Placeholder for libpq's connection type.
Definition: types.hxx:429
concept char_type
Concept: one of the "char" types.
Definition: types.hxx:406
The home of all libpqxx classes, functions, templates, etc.
Definition: array.cxx:26
concept binary
Concept: Binary string, akin to std::string for binary data.
Definition: types.hxx:173
unsigned int oid
PostgreSQL database row identifier.
Definition: types.hxx:73
constexpr oid oid_none
The "null" oid.
Definition: util.hxx:283
int64_t large_object_size_type
Number of bytes in a large object.
Definition: types.hxx:92
format
Format code: is data text or binary?
Definition: types.hxx:121