# 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-2009, 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 *RawConnection(const dbtransaction &T)
    00138   {
    00139     return T.conn().RawConnection();
    00140   }
    00141
    00142   PGSTD::string Reason(int err) const;
    00143
    00144 private:
    00145   oid m_ID;
    00146 };
    00147
    00148
    00149 // TODO: New hierarchy with separate read / write / mixed-mode access
    00150
    00152 class PQXX_LIBEXPORT largeobjectaccess : private largeobject
    00153 {
    00154 public:
    00155   using largeobject::size_type;
    00156   typedef long off_type;
    00157   typedef size_type pos_type;
    00158
    00160
    00164   typedef PGSTD::ios::openmode openmode;
    00165
    00167
    00171   typedef PGSTD::ios::seekdir seekdir;
    00172
    00174
    00178   explicit largeobjectaccess(dbtransaction &T,
    00179                              openmode mode =
    00180                                 PGSTD::ios::in |
    00181                                 PGSTD::ios::out);                       //[t51]
    00182
    00184
    00190   largeobjectaccess(dbtransaction &T,
    00191                     oid O,
    00192                     openmode mode =
    00193                         PGSTD::ios::in |
    00194                         PGSTD::ios::out);                               //[t52]
    00195
    00197
    00202   largeobjectaccess(dbtransaction &T,
    00203                     largeobject O,
    00204                     openmode mode = PGSTD::ios::in | PGSTD::ios::out);  //[t50]
    00205
    00207
    00212   largeobjectaccess(dbtransaction &T,
    00213                     const PGSTD::string &File,
    00214                     openmode mode =
    00215                         PGSTD::ios::in | PGSTD::ios::out);              //[t55]
    00216
    00217   ~largeobjectaccess() throw () { close(); }
    00218
    00220
    00223   using largeobject::id;
    00224
    00226
    00229   void to_file(const PGSTD::string &File) const                         //[t54]
    00230         { largeobject::to_file(m_Trans, File); }
    00231
    00232 #ifdef PQXX_BROKEN_USING_DECL
    00234
    00238   void to_file(dbtransaction &T, const PGSTD::string &F) const
    00239         { largeobject::to_file(T, F); }
    00240 #else
    00241   using largeobject::to_file;
    00242 #endif
    00243
    00248
    00249
    00253   void write(const char Buf[], size_type Len);                          //[t51]
    00254
    00256
    00259   void write(const PGSTD::string &Buf)                                  //[t50]
    00260         { write(Buf.c_str(), static_cast<size_type>(Buf.size())); }
    00261
    00263
    00269   size_type read(char Buf[], size_type Len);                            //[t50]
    00270
    00272
    00275   size_type seek(size_type dest, seekdir dir);                          //[t51]
    00276
    00278
    00281   size_type tell() const;                                               //[t50]
    00283
    00293
    00294
    00302   pos_type cseek(off_type dest, seekdir dir) throw ();                  //[t50]
    00303
    00305
    00311   off_type cwrite(const char Buf[], size_type Len) throw ();            //[t50]
    00312
    00314
    00320   off_type cread(char Buf[], size_type Len) throw ();                   //[t50]
    00321
    00323
    00327   pos_type ctell() const throw ();                                      //[t50]
    00329
    00334
    00335   void process_notice(const PGSTD::string &) throw ();                  //[t50]
    00337
    00338   using largeobject::remove;
    00339
    00340   using largeobject::operator==;
    00341   using largeobject::operator!=;
    00342   using largeobject::operator<;
    00343   using largeobject::operator<=;
    00344   using largeobject::operator>;
    00345   using largeobject::operator>=;
    00346
    00347 private:
    00348   PGSTD::string PQXX_PRIVATE Reason(int err) const;
    00349   internal::pq::PGconn *RawConnection() const
    00350         { return largeobject::RawConnection(m_Trans); }
    00351
    00352   void open(openmode mode);
    00353   void close() throw ();
    00354
    00355   dbtransaction &m_Trans;
    00356   int m_fd;
    00357
    00358   // Not allowed:
    00359   largeobjectaccess();
    00360   largeobjectaccess(const largeobjectaccess &);
    00361   largeobjectaccess operator=(const largeobjectaccess &);
    00362 };
    00363
    00364
    00366
    00374 template<typename CHAR=char, typename TRAITS=PGSTD::char_traits<CHAR> >
    00375   class largeobject_streambuf :
    00376 #ifdef PQXX_HAVE_STREAMBUF
    00377     public PGSTD::basic_streambuf<CHAR, TRAITS>
    00378 #else
    00379     public PGSTD::streambuf
    00380 #endif
    00381 {
    00382   typedef long size_type;
    00383 public:
    00384   typedef CHAR   char_type;
    00385   typedef TRAITS traits_type;
    00386   typedef typename traits_type::int_type int_type;
    00387 #ifdef PQXX_HAVE_STREAMBUF
    00388   typedef typename traits_type::pos_type pos_type;
    00389   typedef typename traits_type::off_type off_type;
    00390 #else
    00391   typedef streamoff off_type;
    00392   typedef streampos pos_type;
    00393 #endif
    00394   typedef largeobjectaccess::openmode openmode;
    00395   typedef largeobjectaccess::seekdir seekdir;
    00396
    00397   largeobject_streambuf(dbtransaction &T,
    00398                         largeobject O,
    00399                         openmode mode = PGSTD::ios::in | PGSTD::ios::out,
    00400                         size_type BufSize=512) :                        //[t48]
    00401     m_BufSize(BufSize),
    00402     m_Obj(T, O),
    00403     m_G(0),
    00404     m_P(0)
    00405         { initialize(mode); }
    00406
    00407   largeobject_streambuf(dbtransaction &T,
    00408                         oid O,
    00409                         openmode mode = PGSTD::ios::in | PGSTD::ios::out,
    00410                         size_type BufSize=512) :                        //[t48]
    00411     m_BufSize(BufSize),
    00412     m_Obj(T, O),
    00413     m_G(0),
    00414     m_P(0)
    00415         { initialize(mode); }
    00416
    00417   virtual ~largeobject_streambuf() throw () { delete [] m_P; delete [] m_G; }
    00418
    00419
    00421   void process_notice(const PGSTD::string &s) { m_Obj.process_notice(s); }
    00422
    00423 #ifdef PQXX_HAVE_STREAMBUF
    00424 protected:
    00425 #endif
    00426   virtual int sync()
    00427   {
    00428     // setg() sets eback, gptr, egptr
    00429     setg(this->eback(), this->eback(), this->egptr());
    00430     return overflow(EoF());
    00431   }
    00432
    00433 protected:
    00434   virtual pos_type seekoff(off_type offset,
    00435                            seekdir dir,
    00436                            openmode)
    00437   {
    00438     return AdjustEOF(m_Obj.cseek(largeobjectaccess::off_type(offset), dir));
    00439   }
    00440
    00441   virtual pos_type seekpos(pos_type pos, openmode)
    00442   {
    00443     const largeobjectaccess::pos_type newpos = m_Obj.cseek(
    00444         largeobjectaccess::off_type(pos),
    00445         PGSTD::ios::beg);
    00446     return AdjustEOF(newpos);
    00447   }
    00448
    00449   virtual int_type overflow(int_type ch = EoF())
    00450   {
    00451     char *const pp = this->pptr();
    00452     if (!pp) return EoF();
    00453     char *const pb = this->pbase();
    00454     int_type res = 0;
    00455
    00456     if (pp > pb) res = int_type(AdjustEOF(m_Obj.cwrite(pb, pp-pb)));
    00457     setp(m_P, m_P + m_BufSize);
    00458
    00459     // Write that one more character, if it's there.
    00460     if (ch != EoF())
    00461     {
    00462       *this->pptr() = char(ch);
    00463       this->pbump(1);
    00464     }
    00465     return res;
    00466   }
    00467
    00468   virtual int_type underflow()
    00469   {
    00470     if (!this->gptr()) return EoF();
    00471     char *const eb = this->eback();
    00472     const int_type res(static_cast<int_type>(AdjustEOF(m_Obj.cread(this->eback(), m_BufSize))));
    00473     setg(eb, eb, eb + ((res==EoF()) ? 0 : res));
    00474     return (!res || (res == EoF())) ? EoF() : *eb;
    00475   }
    00476
    00477 private:
    00479   static int_type EoF() { return traits_type::eof(); }
    00480
    00482   template<typename INTYPE>
    00483   static PGSTD::streampos AdjustEOF(INTYPE pos)
    00484         { return (pos==-1) ? PGSTD::streampos(EoF()) : PGSTD::streampos(pos); }
    00485
    00486   void initialize(openmode mode)
    00487   {
    00488     if (mode & PGSTD::ios::in)
    00489     {
    00490       m_G = new char_type[m_BufSize];
    00491       setg(m_G, m_G, m_G);
    00492     }
    00493     if (mode & PGSTD::ios::out)
    00494     {
    00495       m_P = new char_type[m_BufSize];
    00496       setp(m_P, m_P + m_BufSize);
    00497     }
    00498   }
    00499
    00500   const size_type m_BufSize;
    00501   largeobjectaccess m_Obj;
    00502
    00503   // Get & put buffers
    00504   char_type *m_G, *m_P;
    00505 };
    00506
    00507
    00509
    00517 template<typename CHAR=char, typename TRAITS=PGSTD::char_traits<CHAR> >
    00518   class basic_ilostream :
    00519 #ifdef PQXX_HAVE_STREAMBUF
    00520     public PGSTD::basic_istream<CHAR, TRAITS>
    00521 #else
    00522     public PGSTD::istream
    00523 #endif
    00524 {
    00525 #ifdef PQXX_HAVE_STREAMBUF
    00526   typedef PGSTD::basic_istream<CHAR, TRAITS> super;
    00527 #else
    00528   typedef PGSTD::istream super;
    00529 #endif
    00530
    00531 public:
    00532   typedef CHAR char_type;
    00533   typedef TRAITS traits_type;
    00534   typedef typename traits_type::int_type int_type;
    00535   typedef typename traits_type::pos_type pos_type;
    00536   typedef typename traits_type::off_type off_type;
    00537
    00539
    00544   basic_ilostream(dbtransaction &T,
    00545                   largeobject O,
    00546                   largeobject::size_type BufSize=512) :                 //[t57]
    00547     super(0),
    00548     m_Buf(T, O, PGSTD::ios::in, BufSize)
    00549         { super::init(&m_Buf); }
    00550
    00552
    00557   basic_ilostream(dbtransaction &T,
    00558                   oid O,
    00559                   largeobject::size_type BufSize=512) :                 //[t48]
    00560     super(0),
    00561     m_Buf(T, O, PGSTD::ios::in, BufSize)
    00562         { super::init(&m_Buf); }
    00563
    00564 private:
    00565   largeobject_streambuf<CHAR,TRAITS> m_Buf;
    00566 };
    00567
    00568 typedef basic_ilostream<char> ilostream;
    00569
    00570
    00572
    00580 template<typename CHAR=char, typename TRAITS=PGSTD::char_traits<CHAR> >
    00581   class basic_olostream :
    00582 #ifdef PQXX_HAVE_STREAMBUF
    00583     public PGSTD::basic_ostream<CHAR, TRAITS>
    00584 #else
    00585     public PGSTD::ostream
    00586 #endif
    00587 {
    00588 #ifdef PQXX_HAVE_STREAMBUF
    00589   typedef PGSTD::basic_ostream<CHAR, TRAITS> super;
    00590 #else
    00591   typedef PGSTD::ostream super;
    00592 #endif
    00593 public:
    00594   typedef CHAR char_type;
    00595   typedef TRAITS traits_type;
    00596   typedef typename traits_type::int_type int_type;
    00597   typedef typename traits_type::pos_type pos_type;
    00598   typedef typename traits_type::off_type off_type;
    00599
    00601
    00606   basic_olostream(dbtransaction &T,
    00607                   largeobject O,
    00608                   largeobject::size_type BufSize=512) :                 //[t48]
    00609     super(0),
    00610     m_Buf(T, O, PGSTD::ios::out, BufSize)
    00611         { super::init(&m_Buf); }
    00612
    00614
    00619   basic_olostream(dbtransaction &T,
    00620                   oid O,
    00621                   largeobject::size_type BufSize=512) :                 //[t57]
    00622     super(0),
    00623     m_Buf(T, O, PGSTD::ios::out, BufSize)
    00624         { super::init(&m_Buf); }
    00625
    00626   ~basic_olostream()
    00627   {
    00628     try
    00629     {
    00630 #ifdef PQXX_HAVE_STREAMBUF
    00631       m_Buf.pubsync(); m_Buf.pubsync();
    00632 #else
    00633       m_Buf.sync(); m_Buf.sync();
    00634 #endif
    00635     }
    00636     catch (const PGSTD::exception &e)
    00637     {
    00638       m_Buf.process_notice(e.what());
    00639     }
    00640   }
    00641
    00642 private:
    00643   largeobject_streambuf<CHAR,TRAITS> m_Buf;
    00644 };
    00645
    00646 typedef basic_olostream<char> olostream;
    00647
    00648
    00650
    00658 template<typename CHAR=char, typename TRAITS=PGSTD::char_traits<CHAR> >
    00659   class basic_lostream :
    00660 #ifdef PQXX_HAVE_STREAMBUF
    00661     public PGSTD::basic_iostream<CHAR, TRAITS>
    00662 #else
    00663     public PGSTD::iostream
    00664 #endif
    00665 {
    00666 #ifdef PQXX_HAVE_STREAMBUF
    00667   typedef PGSTD::basic_iostream<CHAR, TRAITS> super;
    00668 #else
    00669   typedef PGSTD::iostream super;
    00670 #endif
    00671
    00672 public:
    00673   typedef CHAR char_type;
    00674   typedef TRAITS traits_type;
    00675   typedef typename traits_type::int_type int_type;
    00676   typedef typename traits_type::pos_type pos_type;
    00677   typedef typename traits_type::off_type off_type;
    00678
    00680
    00685   basic_lostream(dbtransaction &T,
    00686                  largeobject O,
    00687                  largeobject::size_type BufSize=512) :                  //[t59]
    00688     super(0),
    00689     m_Buf(T, O, PGSTD::ios::in | PGSTD::ios::out, BufSize)
    00690         { super::init(&m_Buf); }
    00691
    00693
    00698   basic_lostream(dbtransaction &T,
    00699                  oid O,
    00700                  largeobject::size_type BufSize=512) :                  //[t59]
    00701     super(0),
    00702     m_Buf(T, O, PGSTD::ios::in | PGSTD::ios::out, BufSize)
    00703         { super::init(&m_Buf); }
    00704
    00705   ~basic_lostream()
    00706   {
    00707     try
    00708     {
    00709 #ifdef PQXX_HAVE_STREAMBUF
    00710       m_Buf.pubsync(); m_Buf.pubsync();
    00711 #else
    00712       m_Buf.sync(); m_Buf.sync();
    00713 #endif
    00714     }
    00715     catch (const PGSTD::exception &e)
    00716     {
    00717       m_Buf.process_notice(e.what());
    00718     }
    00719   }
    00720
    00721 private:
    00722   largeobject_streambuf<CHAR,TRAITS> m_Buf;
    00723 };
    00724
    00725 typedef basic_lostream<char> lostream;
    00726
    00727 } // namespace pqxx
    00728
    00729 #include "pqxx/compiler-internal-post.hxx"
    00730
    00731 #endif
    00732