Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

result.hxx

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  *   FILE
00004  *      pqxx/result.hxx
00005  *
00006  *   DESCRIPTION
00007  *      definitions for the pqxx::result class and support classes.
00008  *   pqxx::result represents the set of result tuples from a database query
00009  *   DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/result instead.
00010  *
00011  * Copyright (c) 2001-2004, 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 #ifdef PQXX_HAVE_IOS
00020 #include <ios>
00021 #endif
00022 
00023 #include <stdexcept>
00024 
00025 #include "pqxx/util"
00026 
00027 /* Methods tested in eg. self-test program test001 are marked with "//[t1]"
00028  */
00029 
00030 // TODO: Support SQL arrays
00031 // TODO: value_type, reference, const_reference
00032 // TODO: container comparisons
00033 
00034 namespace pqxx
00035 {
00036 
00038 
00045 class PQXX_LIBEXPORT result
00046 {
00047 public:
00048   result() throw () : m_Result(0), m_l(this), m_r(this) {}              //[t3]
00049   result(const result &rhs) throw () :                                  //[t1]
00050           m_Result(0), m_l(this), m_r(this) { MakeRef(rhs); }
00051   ~result() { LoseRef(); }                                              //[t1]
00052   
00053   result &operator=(const result &) throw ();                           //[t10]
00054 
00055   typedef unsigned long size_type;
00056   typedef signed long difference_type;
00057   class field;
00058   class const_fielditerator;
00059 
00061 
00071   class PQXX_LIBEXPORT tuple
00072   {
00073   public:
00074     typedef unsigned int size_type;
00075     typedef signed int difference_type;
00076     typedef const_fielditerator const_iterator;
00077 
00078     tuple(const result *r, result::size_type i) throw () : 
00079       m_Home(r), m_Index(i) {}
00080     ~tuple() throw () {} // Yes Scott Meyers, you're absolutely right[1]
00081 
00082     inline const_iterator begin() const throw ();                       //[t82]
00083     inline const_iterator end() const throw ();                         //[t82]
00084 
00085 #ifdef PQXX_HAVE_REVERSE_ITERATOR
00086     typedef PGSTD::reverse_iterator<const_iterator> const_reverse_iterator;
00087     const_reverse_iterator rbegin() const                               //[t82]
00088         { return const_reverse_iterator(end()); }
00089     const_reverse_iterator rend() const                                 //[t82]
00090         { return const_reverse_iterator(begin()); }
00091 #endif
00092 
00093     inline field operator[](size_type) const throw ();                  //[]
00094     inline field operator[](int i) const throw ()                       //[]
00095         { return operator[](size_type(i)); }
00096     field operator[](const char[]) const;                               //[t11]
00097     field operator[](const PGSTD::string &s) const                      //[t11]
00098         { return operator[](s.c_str()); }
00099     field at(size_type) const throw (PGSTD::out_of_range);              //[]
00100     field at(int i) const throw (PGSTD::out_of_range)                   //[]
00101         { return at(size_type(i)); }
00102     field at(const char[]) const;                                       //[t11]
00103     field at(const PGSTD::string &s) const { return at(s.c_str()); }    //[t11]
00104 
00105     inline size_type size() const throw ();                             //[t11]
00106 
00107     result::size_type rownumber() const throw () { return m_Index; }    //[t11]
00108 
00110     size_type column_number(const PGSTD::string &ColName) const         //[t30]
00111         { return m_Home->column_number(ColName); }
00112 
00114     size_type column_number(const char ColName[]) const                 //[t30]
00115         { return m_Home->column_number(ColName); }
00116 
00118     oid column_type(size_type ColNum) const                             //[]
00119         { return m_Home->column_type(ColNum); }
00120 
00122     oid column_type(int ColNum) const                                   //[]
00123         { return column_type(size_type(ColNum)); }
00124 
00126     oid column_type(const PGSTD::string &ColName) const                 //[t7]
00127         { return column_type(column_number(ColName)); }
00128 
00130     oid column_type(const char ColName[]) const                         //[t7]
00131         { return column_type(column_number(ColName)); }
00132 
00133     result::size_type num() const { return rownumber(); }               //[t1]
00134 
00135 #ifdef PQXX_HAVE_PQFTABLE
00136     oid column_table(size_type ColNum) const                            //[]
00137         { return m_Home->column_table(ColNum); }
00138     oid column_table(int ColNum) const                                  //[]
00139         { return column_table(size_type(ColNum)); }
00140     oid column_table(const PGSTD::string &ColName) const                //[t2]
00141         { return column_table(column_number(ColName)); }
00142 #endif
00143 
00144 
00145 #ifdef PQXX_DEPRECATED_HEADERS
00146 
00147     result::size_type Row() const { return rownumber(); }
00148 
00150     size_type ColumnNumber(const PGSTD::string &ColName) const 
00151         { return m_Home->ColumnNumber(ColName); }
00152 
00154     size_type ColumnNumber(const char ColName[]) const 
00155         { return m_Home->ColumnNumber(ColName); }
00156 #endif
00157 
00158 
00159   protected:
00160     friend class field;
00161     const result *m_Home;
00162     result::size_type m_Index;
00163 
00164     // Not allowed:
00165     tuple();
00166   };
00167 
00169 
00172   class PQXX_LIBEXPORT field
00173   {
00174   public:
00175     typedef size_t size_type;
00176 
00178 
00182     field(const tuple &T, tuple::size_type C) throw () :                //[t1]
00183         m_tup(T), m_col(C) {}
00184 
00186 
00191     const char *c_str() const {return home()->GetValue(idx(),col());}   //[t2]
00192 
00194     inline const char *name() const;                                    //[t11]
00195 
00197     oid type() const                                                    //[t7]
00198         { return home()->column_type(col()); }
00199 
00200 #ifdef PQXX_HAVE_PQFTABLE
00201 
00202 
00204     oid table() const { return home()->column_table(col()); }           //[t2]
00205 #endif
00206 
00208 
00217     template<typename T> bool to(T &Obj) const                          //[t3]
00218     {
00219       if (is_null())
00220         return false;
00221 
00222       try
00223       {
00224         from_string(c_str(), Obj);
00225       }
00226       catch (const PGSTD::exception &e)
00227       {
00228         throw PGSTD::domain_error("Error reading field " + 
00229                                   PGSTD::string(name()) +
00230                                   ": " +
00231                                   e.what());
00232       }
00233       return true;
00234     }
00235 
00237     template<typename T> bool operator>>(T &Obj) const                  //[t7]
00238         { return to(Obj); }
00239 
00240 #ifdef PQXX_NO_PARTIAL_CLASS_TEMPLATE_SPECIALISATION
00241 
00242     template<> bool to<PGSTD::string>(PGSTD::string &Obj) const;
00243 
00245 
00248     template<> bool to<const char *>(const char *&Obj) const;
00249 #endif
00250 
00251 
00253     template<typename T> bool to(T &Obj, const T &Default) const        //[t12]
00254     {
00255       const bool NotNull = to(Obj);
00256       if (!NotNull)
00257         Obj = Default;
00258       return NotNull;
00259     }
00260 
00262 
00265     template<typename T> T as(const T &Default) const                   //[t1]
00266     {
00267       T Obj;
00268       to(Obj, Default);
00269       return Obj;
00270     }
00271 
00273     template<typename T> T as() const                                   //[t45]
00274     {
00275       T Obj;
00276       const bool NotNull = to(Obj);
00277       if (!NotNull) throw PGSTD::domain_error("Attempt to read null field");
00278       return Obj;
00279     }
00280 
00281     bool is_null() const { return home()->GetIsNull(idx(),col()); }     //[t12]
00282 
00283     size_type size() const { return home()->GetLength(idx(),col()); }   //[t11]
00284 
00285     tuple::size_type num() const { return col(); }                      //[t82]
00286 
00287 #ifdef PQXX_DEPRECATED_HEADERS
00288 
00289     const char *Name() const {return name();}
00290 #endif
00291 
00292   private:
00293     const result *home() const throw () { return m_tup.m_Home; }
00294     result::size_type idx() const throw () { return m_tup.m_Index; }
00295 
00296   protected:
00297     const tuple::size_type col() const throw () { return m_col; }
00298     tuple m_tup;
00299     tuple::size_type m_col;
00300   };
00301 
00303 
00307   class PQXX_LIBEXPORT const_iterator : 
00308     public PGSTD::iterator<PGSTD::random_access_iterator_tag, 
00309                          const tuple,
00310                          result::size_type>, 
00311     public tuple
00312   {
00313   public:
00314     typedef result::size_type size_type;
00315     typedef result::difference_type difference_type;
00316 
00317     const_iterator() throw () : tuple(0,0) {}
00318     const_iterator(const tuple &t) throw () : tuple(t) {}
00319 
00326     pointer operator->()  const { return this; }                        //[t12]
00327     reference operator*() const { return *operator->(); }               //[t12]
00328 
00329     const_iterator operator++(int);                                     //[t12]
00330     const_iterator &operator++() { ++m_Index; return *this; }           //[t1]
00331     const_iterator operator--(int);                                     //[t12]
00332     const_iterator &operator--() { --m_Index; return *this; }           //[t12]
00333 
00334     const_iterator &operator+=(difference_type i)                       //[t12]
00335         { m_Index+=i; return *this; }
00336     const_iterator &operator-=(difference_type i)                       //[t12]
00337         { m_Index-=i; return *this; }
00338 
00339     bool operator==(const const_iterator &i) const                      //[t12]
00340         {return m_Index==i.m_Index;}
00341     bool operator!=(const const_iterator &i) const                      //[t12]
00342         {return m_Index!=i.m_Index;}
00343     bool operator<(const const_iterator &i) const                       //[t12]
00344          {return m_Index<i.m_Index;}
00345     bool operator<=(const const_iterator &i) const                      //[t12]
00346         {return m_Index<=i.m_Index;}
00347     bool operator>(const const_iterator &i) const                       //[t12]
00348         {return m_Index>i.m_Index;}
00349     bool operator>=(const const_iterator &i) const                      //[t12]
00350         {return m_Index>=i.m_Index;}
00351 
00352     inline const_iterator operator+(difference_type) const;             //[t12]
00353 
00354     friend const_iterator operator+(difference_type, const_iterator);   //[t12]
00355 
00356     inline const_iterator operator-(difference_type) const;             //[t12]
00357 
00358     inline difference_type operator-(const_iterator) const;             //[t12]
00359 
00360   private:
00361     friend class result;
00362     const_iterator(const result *r, result::size_type i) : tuple(r, i) {}
00363   };
00364 
00365   class PQXX_LIBEXPORT const_fielditerator : 
00366     public PGSTD::iterator<PGSTD::random_access_iterator_tag, 
00367                          const field,
00368                          tuple::size_type>, 
00369     public field
00370   {
00371     typedef PGSTD::iterator<PGSTD::random_access_iterator_tag,
00372                                 const field,
00373                                 tuple::size_type> it;
00374   public:
00375     typedef tuple::size_type size_type;
00376     typedef tuple::difference_type difference_type;
00377     using it::pointer;
00378     using it::reference;
00379 
00380     const_fielditerator(const tuple &T, tuple::size_type C) throw () :  //[t82]
00381       field(T, C) {}
00382     const_fielditerator(const field &F) throw () : field(F) {}          //[t82]
00383 
00384     pointer operator->() const { return this; }                         //[t82]
00385     reference operator*() const { return *operator->(); }               //[t82]
00386 
00387     const_fielditerator operator++(int);                                //[t82]
00388     const_fielditerator &operator++() { ++m_col; return *this; }        //[t82]
00389     const_fielditerator operator--(int);                                //[t82]
00390     const_fielditerator &operator--() { --m_col; return *this; }        //[t82]
00391 
00392     const_fielditerator &operator+=(difference_type i)                  //[t82]
00393         { m_col+=i; return *this; }
00394     const_fielditerator &operator-=(difference_type i)                  //[t82]
00395         { m_col-=i; return *this; }
00396 
00397     bool operator==(const const_fielditerator &i) const                 //[t82]
00398         {return col()==i.col();}
00399     bool operator!=(const const_fielditerator &i) const                 //[t82]
00400         {return col()!=i.col();}
00401     bool operator<(const const_fielditerator &i) const                  //[t82]
00402          {return col()<i.col();}
00403     bool operator<=(const const_fielditerator &i) const                 //[t82]
00404         {return col()<=i.col();}
00405     bool operator>(const const_fielditerator &i) const                  //[t82]
00406         {return col()>i.col();}
00407     bool operator>=(const const_fielditerator &i) const                 //[t82]
00408         {return col()>=i.col();}
00409 
00410     inline const_fielditerator operator+(difference_type) const;        //[t82]
00411 
00412     friend const_fielditerator operator+(difference_type, 
00413                                     const_fielditerator);               //[t82]
00414 
00415     inline const_fielditerator operator-(difference_type) const;        //[t82]
00416 
00417     inline difference_type operator-(const_fielditerator) const;        //[t82]
00418   };
00419 
00420 
00421 #ifdef PQXX_HAVE_REVERSE_ITERATOR
00422   typedef PGSTD::reverse_iterator<const_iterator> const_reverse_iterator;
00423   const_reverse_iterator rbegin() const                                 //[t75]
00424         { return const_reverse_iterator(end()); }
00425   const_reverse_iterator rend() const                                   //[t75]
00426         { return const_reverse_iterator(begin()); }
00427 #endif
00428 
00429   const_iterator begin() const { return const_iterator(this, 0); }      //[t1]
00430   inline const_iterator end() const;                                    //[t1]
00431 
00432   size_type size() const                                                //[t2]
00433         { return m_Result ? PQXXPQ::PQntuples(m_Result) : 0; }
00434   bool empty() const                                                    //[t11]
00435         { return !m_Result || !PQXXPQ::PQntuples(m_Result); }
00436   size_type capacity() const { return size(); }                         //[t20]
00437 
00438   void swap(result &other) throw ();                                    //[t77]
00439 
00440   const tuple operator[](size_type i) const throw ()                    //[t2]
00441         { return tuple(this, i); }
00442   const tuple at(size_type) const throw (PGSTD::out_of_range);          //[t10]
00443 
00444   void clear() throw () { LoseRef(); }                                  //[t20]
00445 
00447   tuple::size_type columns() const throw ()                             //[t11]
00448         { return PQnfields(m_Result); }
00449 
00451   tuple::size_type column_number(const char ColName[]) const;           //[t11]
00452 
00454   tuple::size_type column_number(const PGSTD::string &Name) const       //[t11]
00455         {return column_number(Name.c_str());}
00456 
00458   const char *column_name(tuple::size_type Number) const;               //[t11]
00459 
00461   inline oid column_type(tuple::size_type ColNum) const;                //[]
00463   inline oid column_type(int ColNum) const                              //[]
00464         { return column_type(tuple::size_type(ColNum)); }
00465 
00467   oid column_type(const PGSTD::string &ColName) const                   //[t7]
00468         { return column_type(column_number(ColName)); }
00469 
00471   oid column_type(const char ColName[]) const                           //[t7]
00472         { return column_type(column_number(ColName)); }
00473 
00474 #ifdef PQXX_HAVE_PQFTABLE
00475 
00476   oid column_table(tuple::size_type ColNum) const;                      //[]
00478   oid column_table(int ColNum) const                                    //[]
00479         { return column_table(tuple::size_type(ColNum)); } 
00480 
00482   oid column_table(const PGSTD::string &ColName) const                  //[t2]
00483         { return column_table(column_number(ColName)); }
00484 #endif
00485 
00487 
00489   oid inserted_oid() const { return PQoidValue(m_Result); }             //[t13]
00490 
00491 
00493   /*** Returns zero for all other commands. */
00494   size_type affected_rows() const;                                      //[t7]
00495 
00496 
00497 #ifdef PQXX_DEPRECATED_HEADERS
00498 
00499   typedef tuple Tuple;
00501   typedef field Field;
00503   oid InsertedOid() const { return inserted_oid(); }
00505   size_type AffectedRows() const { return affected_rows(); }
00507   tuple::size_type Columns() const { return columns(); }
00509   tuple::size_type ColumnNumber(const char Name[]) const
00510         {return PQfnumber(m_Result,Name);}
00512   tuple::size_type ColumnNumber(const PGSTD::string &Name) const
00513         {return ColumnNumber(Name.c_str());}
00515   const char *ColumnName(tuple::size_type Number) const
00516         {return PQfname(m_Result,Number);}
00517 #endif
00518 
00519 
00520 private:
00521   internal::pq::PGresult *m_Result;
00522   mutable const result *m_l, *m_r;
00523 
00524   friend class result::field;
00525   const char *GetValue(size_type Row, tuple::size_type Col) const;
00526   bool GetIsNull(size_type Row, tuple::size_type Col) const;
00527   field::size_type GetLength(size_type Row, tuple::size_type Col) const;
00528 
00529   friend class connection_base;
00530   friend class pipeline;
00531   explicit result(internal::pq::PGresult *rhs) throw () : 
00532     m_Result(0), m_l(this), m_r(this) {MakeRef(rhs);}
00533   result &operator=(internal::pq::PGresult *) throw ();
00534   bool operator!() const throw () { return !m_Result; }
00535   operator bool() const throw () { return m_Result != 0; }
00536   void CheckStatus(const PGSTD::string &Query) const;
00537   void CheckStatus(const char Query[]) const;
00538   int errorposition() const throw ();
00539   PGSTD::string StatusError() const;
00540 
00541   friend class Cursor;
00542   const char *CmdStatus() const throw () { return PQcmdStatus(m_Result); }
00543 
00544 
00545   void MakeRef(internal::pq::PGresult *) throw ();
00546   void MakeRef(const result &) throw ();
00547   void LoseRef() throw ();
00548 };
00549 
00550 
00552 
00569 template<typename STREAM>
00570 inline STREAM &operator<<(STREAM &S, const pqxx::result::field &F)      //[t46]
00571 {
00572   S.write(F.c_str(), F.size());
00573   return S;
00574 }
00575 
00576 
00578 template<typename T>
00579 inline void from_string(const result::field &F, T &Obj)                 //[t46]
00580         { from_string(F.c_str(), Obj); }
00581 
00583 template<>
00584 inline PGSTD::string to_string(const result::field &Obj)                //[t74]
00585         { return to_string(Obj.c_str()); }
00586 
00587 
00588 
00589 inline result::tuple::const_iterator
00590 result::tuple::begin() const throw ()
00591         { return tuple::const_iterator(*this, 0); }
00592 
00593 inline result::tuple::const_iterator
00594 result::tuple::end() const throw ()
00595         { return tuple::const_iterator(*this, size()); }
00596 
00597 inline result::field 
00598 result::tuple::operator[](result::tuple::size_type i) const  throw ()
00599         { return field(*this, i); }
00600 
00601 inline result::tuple::size_type result::tuple::size() const throw ()
00602         { return m_Home->columns(); }
00603 
00604 inline const char *result::field::name() const 
00605         { return home()->column_name(col()); }
00606 
00608 template<> 
00609 inline bool result::field::to<PGSTD::string>(PGSTD::string &Obj) const
00610 {
00611   if (is_null()) return false;
00612   Obj = c_str();
00613   return true;
00614 }
00615 
00617 
00620 template<> 
00621 inline bool result::field::to<const char *>(const char *&Obj) const
00622 {
00623   if (is_null()) return false;
00624   Obj = c_str();
00625   return true;
00626 }
00627 
00628 
00629 inline result::const_iterator 
00630 result::const_iterator::operator+(difference_type o) const
00631 {
00632   return const_iterator(m_Home, m_Index + o);
00633 }
00634 
00635 inline result::const_iterator 
00636 operator+(result::const_iterator::difference_type o, 
00637           result::const_iterator i)
00638 {
00639   return i + o;
00640 }
00641 
00642 inline result::const_iterator 
00643 result::const_iterator::operator-(difference_type o) const
00644 {
00645   return const_iterator(m_Home, m_Index - o);
00646 }
00647 
00648 inline result::const_iterator::difference_type 
00649 result::const_iterator::operator-(const_iterator i) const
00650 { 
00651   return num()-i.num(); 
00652 }
00653 
00654 inline result::const_iterator result::end() const 
00655 { 
00656   return const_iterator(this, size()); 
00657 }
00658 
00659 inline oid result::column_type(tuple::size_type ColNum) const
00660 {
00661   const oid T = PQftype(m_Result, ColNum);
00662   if (T == oid_none)
00663     throw PGSTD::invalid_argument(
00664                 "Attempt to retrieve type of nonexistant column " +
00665                 to_string(ColNum) + " "
00666                 "of query result");
00667   return T;
00668 }
00669 
00670 
00671 inline result::const_fielditerator 
00672 result::const_fielditerator::operator+(difference_type o) const
00673 {
00674   return const_fielditerator(m_tup, col() + o);
00675 }
00676 
00677 inline result::const_fielditerator 
00678 operator+(result::const_fielditerator::difference_type o,
00679           result::const_fielditerator i)
00680 {
00681   return i + o;
00682 }
00683 
00684 inline result::const_fielditerator 
00685 result::const_fielditerator::operator-(difference_type o) const
00686 {
00687   return const_fielditerator(m_tup, col() - o);
00688 }
00689 
00690 inline result::const_fielditerator::difference_type 
00691 result::const_fielditerator::operator-(const_fielditerator i) const
00692 { 
00693   return num()-i.num(); 
00694 }
00695 
00696 
00697 
00698 #ifdef PQXX_HAVE_PQFTABLE
00699 inline oid result::column_table(tuple::size_type ColNum) const
00700 {
00701   const oid T = PQftable(m_Result, ColNum);
00702 
00703   /* If we get oid_none, it may be because the column is computed, or because
00704    * we got an invalid row number.
00705    */
00706   // TODO: Skip this if we first computed the column name ourselves
00707   if ((T == oid_none) &&
00708       (ColNum >= columns()))
00709     throw PGSTD::invalid_argument("Attempt to retrieve table ID for column " +
00710                                   to_string(ColNum) + " "
00711                                   "out of " + to_string(columns()));
00712   return T;
00713 }
00714 #endif
00715 
00716 
00717 template<typename CHAR=char, typename TRAITS=PGSTD::char_traits<CHAR> >
00718   class field_streambuf :
00719 #ifdef PQXX_HAVE_STREAMBUF
00720   public PGSTD::basic_streambuf<CHAR, TRAITS>
00721 #else
00722   public PGSTD::streambuf
00723 #endif
00724 {
00725 public:
00726   typedef CHAR char_type;
00727   typedef TRAITS traits_type;
00728   typedef typename traits_type::int_type int_type;
00729 #ifdef PQXX_HAVE_STREAMBUF
00730   typedef typename traits_type::pos_type pos_type;
00731   typedef typename traits_type::off_type off_type;
00732 #else
00733   typedef streamoff off_type;
00734   typedef streampos pos_type;
00735 #endif
00736   typedef PGSTD::ios::openmode openmode;
00737   typedef PGSTD::ios::seekdir seekdir;
00738 
00739   explicit field_streambuf(const result::field &F) :                    //[t74]
00740     m_Field(F)
00741   {
00742     initialize();
00743   }
00744 
00745 #ifdef PQXX_HAVE_STREAMBUF
00746 protected:
00747 #endif
00748   virtual int sync() { return traits_type::eof(); }
00749 
00750 protected:
00751   virtual pos_type seekoff(off_type, seekdir, openmode)
00752   {
00753     return traits_type::eof();
00754   }
00755 
00756   virtual pos_type seekpos(pos_type, openmode) {return traits_type::eof();}
00757 
00758   virtual int_type overflow(int_type) { return traits_type::eof(); }
00759 
00760   virtual int_type underflow() { return traits_type::eof(); }
00761 
00762 private:
00763   const result::field &m_Field;
00764 
00765   int_type initialize()
00766   {
00767     char_type *G = 
00768       reinterpret_cast<char_type *>(const_cast<char *>(m_Field.c_str()));
00769     setg(G, G, G + m_Field.size());
00770     return m_Field.size();
00771   }
00772 };
00773 
00774 
00776 
00790 template<typename CHAR=char, typename TRAITS=PGSTD::char_traits<CHAR> >
00791   class basic_fieldstream :
00792 #ifdef PQXX_HAVE_STREAMBUF
00793     public PGSTD::basic_istream<CHAR, TRAITS>
00794 #else
00795     public PGSTD::istream
00796 #endif
00797 {
00798 #ifdef PQXX_HAVE_STREAMBUF
00799   typedef PGSTD::basic_istream<CHAR, TRAITS> super;
00800 #else
00801   typedef PGSTD::istream super;
00802 #endif
00803 
00804 public:
00805   typedef CHAR char_type;
00806   typedef TRAITS traits_type;
00807   typedef typename traits_type::int_type int_type;
00808   typedef typename traits_type::pos_type pos_type;
00809   typedef typename traits_type::off_type off_type;
00810 
00811   basic_fieldstream(const result::field &F) : super(&m_Buf), m_Buf(F) { }
00812 
00813 private:
00814   field_streambuf<CHAR, TRAITS> m_Buf;
00815 };
00816 
00817 typedef basic_fieldstream<char> fieldstream;
00818 
00819 } // namespace pqxx
00820 
00821 
00822 
00823 /* 
00824 [1] Scott Meyers, in one of his essential books, "Effective C++" and "More 
00825 Effective C++", points out that it is good style to have any class containing 
00826 a member of pointer type define its own destructor--just to show that it knows
00827 what it is doing.  This helps prevent nasty memory leak / double deletion bugs
00828 typically resulting from programmers' omission to deal with such issues in
00829 their destructors.
00830 
00831 The -Weffc++ option in gcc generates warnings for noncompliance with Scott's
00832 style guidelines, and hence necessitates the definition of this destructor,\
00833 trivial as it may be.
00834 
00835 [2] IIRC Alex Stepanov, the inventor of the STL, once remarked that having
00836 this as standard behaviour for pointers would be useful in some algorithms.
00837 So even if this makes me look foolish, I would seem to be in distinguished 
00838 company.
00839 */
00840 
00841 

Generated on Thu Oct 14 20:43:29 2004 for libpqxx by  doxygen 1.3.9