libpqxx 4.0
largeobject.hxx
00001 /*-------------------------------------------------------------------------
00002  *
00003  *   FILE
00004  *      pqxx/largeobject.hxx
00005  *
00006  *   DESCRIPTION
00007  *      libpqxx's Large Objects interface
00008  *   Allows access to large objects directly, or through I/O streams
00009  *   DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/largeobject instead.
00010  *
00011  * Copyright (c) 2003-2011, Jeroen T. Vermeulen <jtv@xs4all.nl>
00012  *
00013  * See COPYING for copyright license.  If you did not receive a file called
00014  * COPYING with this source code, please notify the distributor of this mistake,
00015  * or contact the author.
00016  *
00017  *-------------------------------------------------------------------------
00018  */
00019 #ifndef PQXX_H_LARGEOBJECT
00020 #define PQXX_H_LARGEOBJECT
00021 
00022 #include "pqxx/compiler-public.hxx"
00023 #include "pqxx/compiler-internal-pre.hxx"
00024 
00025 #ifdef PQXX_HAVE_STREAMBUF
00026 #include <streambuf>
00027 #else
00028 #include <streambuf.h>
00029 #endif
00030 
00031 #include "pqxx/dbtransaction"
00032 
00033 
00034 namespace pqxx
00035 {
00036 
00037 class largeobjectaccess;
00038 
00040 
00047 class PQXX_LIBEXPORT largeobject
00048 {
00049 public:
00050   typedef long size_type;
00051 
00053   largeobject() throw ();                                               //[t48]
00054 
00056 
00058   explicit largeobject(dbtransaction &T);                               //[t48]
00059 
00061 
00065   explicit largeobject(oid O) throw () : m_ID(O) {}                     //[t48]
00066 
00068 
00072   largeobject(dbtransaction &T, const PGSTD::string &File);             //[t53]
00073 
00075 
00079   largeobject(const largeobjectaccess &O) throw ();                     //[t50]
00080 
00082 
00086   oid id() const throw () { return m_ID; }                              //[t48]
00087 
00096 
00097 
00098   bool operator==(const largeobject &other) const                       //[t51]
00099           { return m_ID == other.m_ID; }
00101 
00102   bool operator!=(const largeobject &other) const                       //[t51]
00103           { return m_ID != other.m_ID; }
00105 
00106   bool operator<=(const largeobject &other) const                       //[t51]
00107           { return m_ID <= other.m_ID; }
00109 
00110   bool operator>=(const largeobject &other) const                       //[t51]
00111           { return m_ID >= other.m_ID; }
00113 
00114   bool operator<(const largeobject &other) const                        //[t51]
00115           { return m_ID < other.m_ID; }
00117 
00118   bool operator>(const largeobject &other) const                        //[t51]
00119           { return m_ID > other.m_ID; }
00121 
00123 
00127   void to_file(dbtransaction &T, const PGSTD::string &File) const;      //[t52]
00128 
00130 
00134   void remove(dbtransaction &T) const;                                  //[t48]
00135 
00136 protected:
00137   static internal::pq::PGconn * PQXX_PURE RawConnection(const dbtransaction &T);
00138 
00139   PGSTD::string Reason(int err) const;
00140 
00141 private:
00142   oid m_ID;
00143 };
00144 
00145 
00146 // TODO: New hierarchy with separate read / write / mixed-mode access
00147 
00149 class PQXX_LIBEXPORT largeobjectaccess : private largeobject
00150 {
00151 public:
00152   using largeobject::size_type;
00153   typedef long off_type;
00154   typedef size_type pos_type;
00155 
00157 
00161   typedef PGSTD::ios::openmode openmode;
00162 
00164 
00168   typedef PGSTD::ios::seekdir seekdir;
00169 
00171 
00175   explicit largeobjectaccess(dbtransaction &T,
00176                              openmode mode =
00177                                 PGSTD::ios::in |
00178                                 PGSTD::ios::out);                       //[t51]
00179 
00181 
00187   largeobjectaccess(dbtransaction &T,
00188                     oid O,
00189                     openmode mode =
00190                         PGSTD::ios::in |
00191                         PGSTD::ios::out);                               //[t52]
00192 
00194 
00199   largeobjectaccess(dbtransaction &T,
00200                     largeobject O,
00201                     openmode mode = PGSTD::ios::in | PGSTD::ios::out);  //[t50]
00202 
00204 
00209   largeobjectaccess(dbtransaction &T,
00210                     const PGSTD::string &File,
00211                     openmode mode =
00212                         PGSTD::ios::in | PGSTD::ios::out);              //[t55]
00213 
00214   ~largeobjectaccess() throw () { close(); }
00215 
00217 
00220   using largeobject::id;
00221 
00223 
00226   void to_file(const PGSTD::string &File) const                         //[t54]
00227         { largeobject::to_file(m_Trans, File); }
00228 
00229 #ifdef PQXX_BROKEN_USING_DECL
00230 
00231 
00235   void to_file(dbtransaction &T, const PGSTD::string &F) const
00236         { largeobject::to_file(T, F); }
00237 #else
00238   using largeobject::to_file;
00239 #endif
00240 
00245 
00246 
00250   void write(const char Buf[], size_type Len);                          //[t51]
00251 
00253 
00256   void write(const PGSTD::string &Buf)                                  //[t50]
00257         { write(Buf.c_str(), static_cast<size_type>(Buf.size())); }
00258 
00260 
00266   size_type read(char Buf[], size_type Len);                            //[t50]
00267 
00269 
00272   size_type seek(size_type dest, seekdir dir);                          //[t51]
00273 
00275 
00278   size_type tell() const;                                               //[t50]
00280 
00290 
00291 
00299   pos_type cseek(off_type dest, seekdir dir) throw ();                  //[t50]
00300 
00302 
00308   off_type cwrite(const char Buf[], size_type Len) throw ();            //[t50]
00309 
00311 
00317   off_type cread(char Buf[], size_type Len) throw ();                   //[t50]
00318 
00320 
00324   pos_type ctell() const throw ();                                      //[t50]
00326 
00331 
00332   void process_notice(const PGSTD::string &) throw ();                  //[t50]
00334 
00335   using largeobject::remove;
00336 
00337   using largeobject::operator==;
00338   using largeobject::operator!=;
00339   using largeobject::operator<;
00340   using largeobject::operator<=;
00341   using largeobject::operator>;
00342   using largeobject::operator>=;
00343 
00344 private:
00345   PGSTD::string PQXX_PRIVATE Reason(int err) const;
00346   internal::pq::PGconn *RawConnection() const
00347         { return largeobject::RawConnection(m_Trans); }
00348 
00349   void open(openmode mode);
00350   void close() throw ();
00351 
00352   dbtransaction &m_Trans;
00353   int m_fd;
00354 
00355   // Not allowed:
00356   largeobjectaccess();
00357   largeobjectaccess(const largeobjectaccess &);
00358   largeobjectaccess operator=(const largeobjectaccess &);
00359 };
00360 
00361 
00363 
00371 template<typename CHAR=char, typename TRAITS=PGSTD::char_traits<CHAR> >
00372   class largeobject_streambuf :
00373 #ifdef PQXX_HAVE_STREAMBUF
00374     public PGSTD::basic_streambuf<CHAR, TRAITS>
00375 #else
00376     public PGSTD::streambuf
00377 #endif
00378 {
00379   typedef long size_type;
00380 public:
00381   typedef CHAR   char_type;
00382   typedef TRAITS traits_type;
00383   typedef typename traits_type::int_type int_type;
00384 #ifdef PQXX_HAVE_STREAMBUF
00385   typedef typename traits_type::pos_type pos_type;
00386   typedef typename traits_type::off_type off_type;
00387 #else
00388   typedef streamoff off_type;
00389   typedef streampos pos_type;
00390 #endif
00391   typedef largeobjectaccess::openmode openmode;
00392   typedef largeobjectaccess::seekdir seekdir;
00393 
00394   largeobject_streambuf(dbtransaction &T,
00395                         largeobject O,
00396                         openmode mode = PGSTD::ios::in | PGSTD::ios::out,
00397                         size_type BufSize=512) :                        //[t48]
00398     m_BufSize(BufSize),
00399     m_Obj(T, O),
00400     m_G(0),
00401     m_P(0)
00402         { initialize(mode); }
00403 
00404   largeobject_streambuf(dbtransaction &T,
00405                         oid O,
00406                         openmode mode = PGSTD::ios::in | PGSTD::ios::out,
00407                         size_type BufSize=512) :                        //[t48]
00408     m_BufSize(BufSize),
00409     m_Obj(T, O),
00410     m_G(0),
00411     m_P(0)
00412         { initialize(mode); }
00413 
00414   virtual ~largeobject_streambuf() throw () { delete [] m_P; delete [] m_G; }
00415 
00416 
00418   void process_notice(const PGSTD::string &s) { m_Obj.process_notice(s); }
00419 
00420 #ifdef PQXX_HAVE_STREAMBUF
00421 protected:
00422 #endif
00423   virtual int sync()
00424   {
00425     // setg() sets eback, gptr, egptr
00426     this->setg(this->eback(), this->eback(), this->egptr());
00427     return overflow(EoF());
00428   }
00429 
00430 protected:
00431   virtual pos_type seekoff(off_type offset,
00432                            seekdir dir,
00433                            openmode)
00434   {
00435     return AdjustEOF(m_Obj.cseek(largeobjectaccess::off_type(offset), dir));
00436   }
00437 
00438   virtual pos_type seekpos(pos_type pos, openmode)
00439   {
00440     const largeobjectaccess::pos_type newpos = m_Obj.cseek(
00441         largeobjectaccess::off_type(pos),
00442         PGSTD::ios::beg);
00443     return AdjustEOF(newpos);
00444   }
00445 
00446   virtual int_type overflow(int_type ch = EoF())
00447   {
00448     char *const pp = this->pptr();
00449     if (!pp) return EoF();
00450     char *const pb = this->pbase();
00451     int_type res = 0;
00452 
00453     if (pp > pb) res = int_type(AdjustEOF(m_Obj.cwrite(pb, pp-pb)));
00454     this->setp(m_P, m_P + m_BufSize);
00455 
00456     // Write that one more character, if it's there.
00457     if (ch != EoF())
00458     {
00459       *this->pptr() = char(ch);
00460       this->pbump(1);
00461     }
00462     return res;
00463   }
00464 
00465   virtual int_type underflow()
00466   {
00467     if (!this->gptr()) return EoF();
00468     char *const eb = this->eback();
00469     const int_type res(static_cast<int_type>(
00470         AdjustEOF(m_Obj.cread(this->eback(), m_BufSize))));
00471     this->setg(eb, eb, eb + ((res==EoF()) ? 0 : res));
00472     return (!res || (res == EoF())) ? EoF() : *eb;
00473   }
00474 
00475 private:
00477   static int_type EoF() { return traits_type::eof(); }
00478 
00480   template<typename INTYPE>
00481   static PGSTD::streampos AdjustEOF(INTYPE pos)
00482         { return (pos==-1) ? PGSTD::streampos(EoF()) : PGSTD::streampos(pos); }
00483 
00484   void initialize(openmode mode)
00485   {
00486     if (mode & PGSTD::ios::in)
00487     {
00488       m_G = new char_type[unsigned(m_BufSize)];
00489       this->setg(m_G, m_G, m_G);
00490     }
00491     if (mode & PGSTD::ios::out)
00492     {
00493       m_P = new char_type[unsigned(m_BufSize)];
00494       this->setp(m_P, m_P + m_BufSize);
00495     }
00496   }
00497 
00498   const size_type m_BufSize;
00499   largeobjectaccess m_Obj;
00500 
00501   // Get & put buffers
00502   char_type *m_G, *m_P;
00503 };
00504 
00505 
00507 
00515 template<typename CHAR=char, typename TRAITS=PGSTD::char_traits<CHAR> >
00516   class basic_ilostream :
00517 #ifdef PQXX_HAVE_STREAMBUF
00518     public PGSTD::basic_istream<CHAR, TRAITS>
00519 #else
00520     public PGSTD::istream
00521 #endif
00522 {
00523 #ifdef PQXX_HAVE_STREAMBUF
00524   typedef PGSTD::basic_istream<CHAR, TRAITS> super;
00525 #else
00526   typedef PGSTD::istream super;
00527 #endif
00528 
00529 public:
00530   typedef CHAR char_type;
00531   typedef TRAITS traits_type;
00532   typedef typename traits_type::int_type int_type;
00533   typedef typename traits_type::pos_type pos_type;
00534   typedef typename traits_type::off_type off_type;
00535 
00537 
00542   basic_ilostream(dbtransaction &T,
00543                   largeobject O,
00544                   largeobject::size_type BufSize=512) :                 //[t57]
00545     super(0),
00546     m_Buf(T, O, PGSTD::ios::in, BufSize)
00547         { super::init(&m_Buf); }
00548 
00550 
00555   basic_ilostream(dbtransaction &T,
00556                   oid O,
00557                   largeobject::size_type BufSize=512) :                 //[t48]
00558     super(0),
00559     m_Buf(T, O, PGSTD::ios::in, BufSize)
00560         { super::init(&m_Buf); }
00561 
00562 private:
00563   largeobject_streambuf<CHAR,TRAITS> m_Buf;
00564 };
00565 
00566 typedef basic_ilostream<char> ilostream;
00567 
00568 
00570 
00578 template<typename CHAR=char, typename TRAITS=PGSTD::char_traits<CHAR> >
00579   class basic_olostream :
00580 #ifdef PQXX_HAVE_STREAMBUF
00581     public PGSTD::basic_ostream<CHAR, TRAITS>
00582 #else
00583     public PGSTD::ostream
00584 #endif
00585 {
00586 #ifdef PQXX_HAVE_STREAMBUF
00587   typedef PGSTD::basic_ostream<CHAR, TRAITS> super;
00588 #else
00589   typedef PGSTD::ostream super;
00590 #endif
00591 public:
00592   typedef CHAR char_type;
00593   typedef TRAITS traits_type;
00594   typedef typename traits_type::int_type int_type;
00595   typedef typename traits_type::pos_type pos_type;
00596   typedef typename traits_type::off_type off_type;
00597 
00599 
00604   basic_olostream(dbtransaction &T,
00605                   largeobject O,
00606                   largeobject::size_type BufSize=512) :                 //[t48]
00607     super(0),
00608     m_Buf(T, O, PGSTD::ios::out, BufSize)
00609         { super::init(&m_Buf); }
00610 
00612 
00617   basic_olostream(dbtransaction &T,
00618                   oid O,
00619                   largeobject::size_type BufSize=512) :                 //[t57]
00620     super(0),
00621     m_Buf(T, O, PGSTD::ios::out, BufSize)
00622         { super::init(&m_Buf); }
00623 
00624   ~basic_olostream()
00625   {
00626     try
00627     {
00628 #ifdef PQXX_HAVE_STREAMBUF
00629       m_Buf.pubsync(); m_Buf.pubsync();
00630 #else
00631       m_Buf.sync(); m_Buf.sync();
00632 #endif
00633     }
00634     catch (const PGSTD::exception &e)
00635     {
00636       m_Buf.process_notice(e.what());
00637     }
00638   }
00639 
00640 private:
00641   largeobject_streambuf<CHAR,TRAITS> m_Buf;
00642 };
00643 
00644 typedef basic_olostream<char> olostream;
00645 
00646 
00648 
00656 template<typename CHAR=char, typename TRAITS=PGSTD::char_traits<CHAR> >
00657   class basic_lostream :
00658 #ifdef PQXX_HAVE_STREAMBUF
00659     public PGSTD::basic_iostream<CHAR, TRAITS>
00660 #else
00661     public PGSTD::iostream
00662 #endif
00663 {
00664 #ifdef PQXX_HAVE_STREAMBUF
00665   typedef PGSTD::basic_iostream<CHAR, TRAITS> super;
00666 #else
00667   typedef PGSTD::iostream super;
00668 #endif
00669 
00670 public:
00671   typedef CHAR char_type;
00672   typedef TRAITS traits_type;
00673   typedef typename traits_type::int_type int_type;
00674   typedef typename traits_type::pos_type pos_type;
00675   typedef typename traits_type::off_type off_type;
00676 
00678 
00683   basic_lostream(dbtransaction &T,
00684                  largeobject O,
00685                  largeobject::size_type BufSize=512) :                  //[t59]
00686     super(0),
00687     m_Buf(T, O, PGSTD::ios::in | PGSTD::ios::out, BufSize)
00688         { super::init(&m_Buf); }
00689 
00691 
00696   basic_lostream(dbtransaction &T,
00697                  oid O,
00698                  largeobject::size_type BufSize=512) :                  //[t59]
00699     super(0),
00700     m_Buf(T, O, PGSTD::ios::in | PGSTD::ios::out, BufSize)
00701         { super::init(&m_Buf); }
00702 
00703   ~basic_lostream()
00704   {
00705     try
00706     {
00707 #ifdef PQXX_HAVE_STREAMBUF
00708       m_Buf.pubsync(); m_Buf.pubsync();
00709 #else
00710       m_Buf.sync(); m_Buf.sync();
00711 #endif
00712     }
00713     catch (const PGSTD::exception &e)
00714     {
00715       m_Buf.process_notice(e.what());
00716     }
00717   }
00718 
00719 private:
00720   largeobject_streambuf<CHAR,TRAITS> m_Buf;
00721 };
00722 
00723 typedef basic_lostream<char> lostream;
00724 
00725 } // namespace pqxx
00726 
00727 #include "pqxx/compiler-internal-post.hxx"
00728 
00729 #endif
00730