Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | 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 #include <stdexcept>
00020 
00021 #include "pqxx/util"
00022 
00023 /* Methods tested in eg. self-test program test001 are marked with "//[t1]"
00024  */
00025 
00026 
00027 // TODO: Support SQL arrays
00028 // TODO: value_type, reference, const_reference, difference_type
00029 // TODO: container comparisons
00030 
00031 namespace pqxx
00032 {
00033 
00035 
00042 class PQXX_LIBEXPORT result
00043 {
00044 public:
00045   result() throw () : m_Result(0), m_Refcount(0) {}                     //[t3]
00046   result(const result &rhs) throw () :                                  //[t1]
00047           m_Result(0), m_Refcount(0) { MakeRef(rhs); }
00048   ~result() { LoseRef(); }                                              //[t1]
00049   
00050   result &operator=(const result &) throw ();                           //[t10]
00051 
00052   typedef result_size_type size_type;
00053   class field;
00054 
00055   // TODO: Field iterators
00056  
00058 
00066   class PQXX_LIBEXPORT tuple
00067   {
00068   public:
00069     typedef tuple_size_type size_type;
00070     tuple(const result *r, result::size_type i) throw () : 
00071       m_Home(r), m_Index(i) {}
00072     ~tuple() throw () {} // Yes Scott Meyers, you're absolutely right[1]
00073 
00074     inline field operator[](size_type) const throw ();                  //[t1]
00075     field operator[](const char[]) const;                               //[t11]
00076     field operator[](const PGSTD::string &s) const                      //[t11]
00077         { return operator[](s.c_str()); }
00078     field at(size_type) const throw (PGSTD::out_of_range);              //[t10]
00079     field at(const char[]) const;                                       //[t11]
00080     field at(const PGSTD::string &s) const { return at(s.c_str()); }    //[t11]
00081 
00082     inline size_type size() const throw ();                             //[t11]
00083 
00084     result::size_type rownumber() const throw () { return m_Index; }    //[t11]
00085 
00087     size_type column_number(const PGSTD::string &ColName) const         //[t30]
00088         { return m_Home->column_number(ColName); }
00089 
00091     size_type column_number(const char ColName[]) const                 //[t30]
00092         { return m_Home->column_number(ColName); }
00093 
00095     oid column_type(size_type ColNum) const                             //[t7]
00096         { return m_Home->column_type(ColNum); }
00097 
00099     oid column_type(const PGSTD::string &ColName) const                 //[t7]
00100         { return column_type(column_number(ColName)); }
00101 
00103     oid column_type(const char ColName[]) const                         //[t7]
00104         { return column_type(column_number(ColName)); }
00105 
00106 #ifdef PQXX_HAVE_PQFTABLE
00107     oid column_table(size_type ColNum) const                            //[t2]
00108         { return m_Home->column_table(ColNum); }
00109     oid column_table(const PGSTD::string &ColName) const                //[t2]
00110         { return column_table(column_number(ColName)); }
00111 #endif
00112 
00113 
00114 #ifdef PQXX_DEPRECATED_HEADERS
00115 
00116     result::size_type Row() const { return rownumber(); }
00117 
00119     size_type ColumnNumber(const PGSTD::string &ColName) const 
00120         { return m_Home->ColumnNumber(ColName); }
00121 
00123     size_type ColumnNumber(const char ColName[]) const 
00124         { return m_Home->ColumnNumber(ColName); }
00125 #endif
00126 
00127 
00128   protected:
00129     const result *m_Home;
00130     result::size_type m_Index;
00131 
00132     // Not allowed:
00133     tuple();
00134   };
00135 
00137 
00140   class PQXX_LIBEXPORT field : private tuple
00141   {
00142   public:
00143     typedef size_t size_type;
00144 
00146 
00150     field(const tuple &R, tuple::size_type C) throw () :                //[t1]
00151         tuple(R), m_Col(C) {}
00152 
00154 
00159     const char *c_str() const {return m_Home->GetValue(m_Index,m_Col);} //[t2]
00160 
00162     inline const char *name() const;                                    //[t11]
00163 
00165     oid type() const                                                    //[t7]
00166         { return m_Home->column_type(m_Col); }
00167 
00168 #ifdef PQXX_HAVE_PQFTABLE
00169 
00170 
00172     oid table() const { return m_Home->column_table(m_Col); }           //[t2]
00173 #endif
00174 
00176 
00185     template<typename T> bool to(T &Obj) const                          //[t3]
00186     {
00187       if (is_null())
00188         return false;
00189 
00190       try
00191       {
00192         FromString(c_str(), Obj);
00193       }
00194       catch (const PGSTD::exception &e)
00195       {
00196         throw PGSTD::domain_error("Error reading field " + 
00197                                   PGSTD::string(name()) +
00198                                   ": " +
00199                                   e.what());
00200       }
00201       return true;
00202     }
00203 
00204 
00205 #ifdef PQXX_NO_PARTIAL_CLASS_TEMPLATE_SPECIALISATION
00206 
00207     template<> bool to<PGSTD::string>(PGSTD::string &Obj) const;
00208 
00210 
00213     template<> bool to<const char *>(const char *&Obj) const;
00214 #endif
00215 
00216 
00218     template<typename T> bool to(T &Obj, const T &Default) const        //[t12]
00219     {
00220       const bool NotNull = to(Obj);
00221       if (!NotNull)
00222         Obj = Default;
00223       return NotNull;
00224     }
00225 
00227 
00230     template<typename T> T as(const T &Default) const                   //[t1]
00231     {
00232       T Obj;
00233       to(Obj, Default);
00234       return Obj;
00235     }
00236 
00238     template<typename T> T as() const                                   //[t45]
00239     {
00240       T Obj;
00241       const bool NotNull = to(Obj);
00242       if (!NotNull) throw PGSTD::domain_error("Attempt to read null field");
00243       return Obj;
00244     }
00245 
00246     bool is_null() const { return m_Home->GetIsNull(m_Index,m_Col); }   //[t12]
00247 
00248     size_type size() const { return m_Home->GetLength(m_Index,m_Col); } //[t11]
00249 
00250 #ifdef PQXX_DEPRECATED_HEADERS
00251 
00252     const char *Name() const {return name();}
00253 #endif
00254 
00255   private:
00256     tuple::size_type m_Col;
00257   };
00258 
00260 
00264   class PQXX_LIBEXPORT const_iterator : 
00265     public PGSTD::iterator<PGSTD::random_access_iterator_tag, 
00266                          const tuple,
00267                          result::size_type>, 
00268     public tuple
00269   {
00270   public:
00271     const_iterator() : tuple(0,0) {}
00272 
00279     pointer operator->()  const { return this; }                        //[t12]
00280     reference operator*() const { return *operator->(); }               //[t12]
00281 
00282     const_iterator operator++(int);                                     //[t12]
00283     const_iterator &operator++() { ++m_Index; return *this; }           //[t1]
00284     const_iterator operator--(int);                                     //[t12]
00285     const_iterator &operator--() { --m_Index; return *this; }           //[t12]
00286 
00287     const_iterator &operator+=(difference_type i)                       //[t12]
00288         { m_Index+=i; return *this; }
00289     const_iterator &operator-=(difference_type i)                       //[t12]
00290         { m_Index-=i; return *this; }
00291 
00292     bool operator==(const const_iterator &i) const                      //[t12]
00293         {return m_Index==i.m_Index;}
00294     bool operator!=(const const_iterator &i) const                      //[t12]
00295         {return m_Index!=i.m_Index;}
00296     bool operator<(const const_iterator &i) const                       //[t12]
00297          {return m_Index<i.m_Index;}
00298     bool operator<=(const const_iterator &i) const                      //[t12]
00299         {return m_Index<=i.m_Index;}
00300     bool operator>(const const_iterator &i) const                       //[t12]
00301         {return m_Index>i.m_Index;}
00302     bool operator>=(const const_iterator &i) const                      //[t12]
00303         {return m_Index>=i.m_Index;}
00304 
00305     inline const_iterator operator+(difference_type o) const;           //[t12]
00306 
00307     friend const_iterator operator+(difference_type o, 
00308                                     const_iterator i);                  //[t12]
00309 
00310     inline const_iterator operator-(difference_type o) const;           //[t12]
00311 
00312     inline difference_type operator-(const_iterator i) const;           //[t12]
00313 
00314     result::size_type num() const { return rownumber(); }               //[t1]
00315 
00316   private:
00317     friend class result;
00318     const_iterator(const result *r, result::size_type i) : tuple(r, i) {}
00319   };
00320 
00321 #ifdef PQXX_HAVE_REVERSE_ITERATOR
00322   typedef PGSTD::reverse_iterator<const_iterator> const_reverse_iterator;
00323   const_reverse_iterator rbegin() const                                 //[t75]
00324         { return const_reverse_iterator(end()); }
00325   const_reverse_iterator rend() const                                   //[t75]
00326         { return const_reverse_iterator(begin()); }
00327 #endif
00328 
00329   const_iterator begin() const { return const_iterator(this, 0); }      //[t1]
00330   inline const_iterator end() const;                                    //[t1]
00331 
00332   size_type size() const { return m_Result ? PQntuples(m_Result) : 0; } //[t2]
00333   bool empty() const { return !m_Result || !PQntuples(m_Result); }      //[t11]
00334   size_type capacity() const { return size(); }                         //[t20]
00335 
00336   const tuple operator[](size_type i) const throw ()                    //[t2]
00337         { return tuple(this, i); }
00338   const tuple at(size_type) const throw (PGSTD::out_of_range);          //[t10]
00339 
00340   void clear() throw () { LoseRef(); }                                  //[t20]
00341 
00343   tuple::size_type columns() const throw ()                             //[t11]
00344         { return PQnfields(m_Result); }
00345 
00347   tuple::size_type column_number(const char ColName[]) const;           //[t11]
00348 
00350   tuple::size_type column_number(const PGSTD::string &Name) const       //[t11]
00351         {return column_number(Name.c_str());}
00352 
00354   const char *column_name(tuple::size_type Number) const;               //[t11]
00355 
00357   inline oid column_type(tuple::size_type ColNum) const;                //[t7]
00358 
00360   oid column_type(const PGSTD::string &ColName) const                   //[t7]
00361         { return column_type(column_number(ColName)); }
00362 
00364   oid column_type(const char ColName[]) const                           //[t7]
00365         { return column_type(column_number(ColName)); }
00366 
00367 #ifdef PQXX_HAVE_PQFTABLE
00368 
00369   oid column_table(tuple::size_type ColNum) const;                      //[t2]
00370 
00372   oid column_table(const PGSTD::string &ColName) const                  //[t2]
00373         { return column_table(column_number(ColName)); }
00374 #endif
00375 
00376 
00378 
00380   oid inserted_oid() const { return PQoidValue(m_Result); }             //[t13]
00381 
00382 
00384   /*** Returns zero for all other commands. */
00385   size_type affected_rows() const;                                      //[t7]
00386 
00387 
00388 #ifdef PQXX_DEPRECATED_HEADERS
00389 
00390   typedef tuple Tuple;
00392   typedef field Field;
00394   oid InsertedOid() const { return inserted_oid(); }
00396   size_type AffectedRows() const { return affected_rows(); }
00398   tuple::size_type Columns() const { return columns(); }
00400   tuple::size_type ColumnNumber(const char Name[]) const
00401         {return PQfnumber(m_Result,Name);}
00403   tuple::size_type ColumnNumber(const PGSTD::string &Name) const
00404         {return ColumnNumber(Name.c_str());}
00406   const char *ColumnName(tuple::size_type Number) const
00407         {return PQfname(m_Result,Number);}
00408 #endif
00409 
00410 
00411 private:
00412   PGresult *m_Result;
00413   mutable int *m_Refcount;
00414 
00415   friend class result::field;
00416   const char *GetValue(size_type Row, tuple::size_type Col) const;
00417   bool GetIsNull(size_type Row, tuple::size_type Col) const;
00418   field::size_type GetLength(size_type Row, tuple::size_type Col) const;
00419 
00420   friend class connection_base;
00421   explicit result(PGresult *rhs) : m_Result(rhs), m_Refcount(0) {MakeRef(rhs);}
00422   result &operator=(PGresult *);
00423   bool operator!() const throw () { return !m_Result; }
00424   operator bool() const throw () { return m_Result != 0; }
00425   friend class pipeline;
00426   void CheckStatus(const PGSTD::string &Query) const;
00427   void CheckStatus(const char Query[]) const;
00428   PGSTD::string StatusError() const;
00429 
00430   friend class Cursor;
00431   const char *CmdStatus() const throw () { return PQcmdStatus(m_Result); }
00432 
00433 
00434   void MakeRef(PGresult *);
00435   void MakeRef(const result &) throw ();
00436   void LoseRef() throw ();
00437 };
00438 
00439 
00441 
00458 template<typename STREAM>
00459 inline STREAM &operator<<(STREAM &S, const pqxx::result::field &F)      //[t46]
00460 {
00461   S.write(F.c_str(), F.size());
00462   return S;
00463 }
00464 
00465 
00466 
00467 inline result::field 
00468 result::tuple::operator[](result::tuple::size_type i) const  throw ()
00469 { 
00470   return field(*this, i); 
00471 }
00472 
00473 inline result::tuple::size_type result::tuple::size() const throw ()
00474 { 
00475   return m_Home->columns(); 
00476 }
00477 
00478 inline const char *result::field::name() const 
00479 { 
00480   return m_Home->column_name(m_Col); 
00481 }
00482 
00484 template<> 
00485 inline bool result::field::to<PGSTD::string>(PGSTD::string &Obj) const
00486 {
00487   if (is_null()) return false;
00488   Obj = c_str();
00489   return true;
00490 }
00491 
00493 
00496 template<> 
00497 inline bool result::field::to<const char *>(const char *&Obj) const
00498 {
00499   if (is_null()) return false;
00500   Obj = c_str();
00501   return true;
00502 }
00503 
00504 
00505 inline result::const_iterator 
00506 result::const_iterator::operator+(difference_type o) const
00507 {
00508   return const_iterator(m_Home, m_Index + o);
00509 }
00510 
00511 inline result::const_iterator 
00512 operator+(result::const_iterator::difference_type o, 
00513           result::const_iterator i)
00514 {
00515   return i + o;
00516 }
00517 
00518 inline result::const_iterator 
00519 result::const_iterator::operator-(difference_type o) const
00520 {
00521   return const_iterator(m_Home, m_Index - o);
00522 }
00523 
00524 inline result::const_iterator::difference_type 
00525 result::const_iterator::operator-(const_iterator i) const
00526 { 
00527   return num()-i.num(); 
00528 }
00529 
00530 inline result::const_iterator result::end() const 
00531 { 
00532   return const_iterator(this, size()); 
00533 }
00534 
00535 inline oid result::column_type(tuple::size_type ColNum) const
00536 {
00537   const oid T = PQftype(m_Result, ColNum);
00538   if (T == oid_none)
00539     throw PGSTD::invalid_argument(
00540                 "Attempt to retrieve type of nonexistant column " +
00541                 ToString(ColNum) + " "
00542                 "of query result");
00543   return T;
00544 }
00545 
00546 
00547 #ifdef PQXX_HAVE_PQFTABLE
00548 inline oid result::column_table(tuple::size_type ColNum) const
00549 {
00550   const oid T = PQftable(m_Result, ColNum);
00551 
00552   /* If we get InvalidOid, it may be because the column is computed, or because
00553    * we got an invalid row number.
00554    */
00555   // TODO: Skip this if we first computed the column name ourselves
00556   if ((T == InvalidOid) &&
00557       ((ColNum < 0) || (ColNum >= columns())))
00558     throw PGSTD::invalid_argument("Attempt to retrieve table ID for column " +
00559                                   ToString(ColNum) + " "
00560                                   "out of " + ToString(columns()));
00561   return T;
00562 }
00563 #endif
00564 
00565 
00566 template<typename CHAR=char, typename TRAITS=PGSTD::char_traits<CHAR> >
00567   class field_streambuf :
00568 #ifdef PQXX_HAVE_STREAMBUF
00569   public PGSTD::basic_streambuf<CHAR, TRAITS>
00570 #else
00571   public PGSTD::streambuf
00572 #endif
00573 {
00574   typedef long size_type;
00575 public:
00576   typedef CHAR char_type;
00577   typedef TRAITS traits_type;
00578   typedef typename traits_type::int_type int_type;
00579 #ifdef PQXX_HAVE_STREAMBUF
00580   typedef typename traits_type::pos_type pos_type;
00581   typedef typename traits_type::off_type off_type;
00582 #else
00583   typedef streamoff off_type;
00584   typedef streampos pos_type;
00585 #endif
00586   typedef PGSTD::ios::openmode openmode;
00587   typedef PGSTD::ios::seekdir seekdir;
00588 
00589   explicit field_streambuf(const result::field &F) :                    //[t74]
00590     m_Field(F)
00591   {
00592     initialize();
00593   }
00594 
00595 #ifdef PQXX_HAVE_STREAMBUF
00596 protected:
00597 #endif
00598   virtual int sync() { return traits_type::eof(); }
00599 
00600 protected:
00601   virtual pos_type seekoff(off_type, seekdir, openmode)
00602   {
00603     return traits_type::eof();
00604   }
00605 
00606   virtual pos_type seekpos(pos_type, openmode) {return traits_type::eof();}
00607 
00608   virtual int_type overflow(int_type) { return traits_type::eof(); }
00609 
00610   // TODO: This isn't good enough with g++ 2.95--it crashes somewhere near here!
00611   virtual int_type underflow() { return initialize(); }
00612 
00613 private:
00614   const result::field &m_Field;
00615 
00616   int_type initialize() throw ()
00617   {
00618     char_type *G = 
00619       reinterpret_cast<char_type *>(const_cast<char *>(m_Field.c_str()));
00620     setg(G, G, G + m_Field.size());
00621     return m_Field.size();
00622   }
00623 };
00624 
00625 
00627 
00641 template<typename CHAR=char, typename TRAITS=PGSTD::char_traits<CHAR> >
00642   class basic_fieldstream :
00643 #ifdef PQXX_HAVE_STREAMBUF
00644     public PGSTD::basic_istream<CHAR, TRAITS>
00645 #else
00646     public PGSTD::istream
00647 #endif
00648 {
00649 #ifdef PQXX_HAVE_STREAMBUF
00650   typedef PGSTD::basic_istream<CHAR, TRAITS> super;
00651 #else
00652   typedef PGSTD::istream super;
00653 #endif
00654 
00655 public:
00656   typedef CHAR char_type;
00657   typedef TRAITS traits_type;
00658   typedef typename traits_type::int_type int_type;
00659   typedef typename traits_type::pos_type pos_type;
00660   typedef typename traits_type::off_type off_type;
00661 
00662   basic_fieldstream(const result::field &F) : super(&m_Buf), m_Buf(F) { }
00663 
00664 private:
00665   field_streambuf<CHAR, TRAITS> m_Buf;
00666 };
00667 
00668 typedef basic_fieldstream<char> fieldstream;
00669 
00670 } // namespace pqxx
00671 
00672 
00673 
00674 /* 
00675 [1] Scott Meyers, in one of his essential books, "Effective C++" and "More 
00676 Effective C++", points out that it is good style to have any class containing 
00677 a member of pointer type define its own destructor--just to show that it knows
00678 what it is doing.  This helps prevent nasty memory leak / double deletion bugs
00679 typically resulting from programmers' omission to deal with such issues in
00680 their destructors.
00681 
00682 The -Weffc++ option in gcc generates warnings for noncompliance with Scott's
00683 style guidelines, and hence necessitates the definition of this destructor,\
00684 trivial as it may be.
00685 
00686 [2] IIRC Alex Stepanov, the inventor of the STL, once remarked that having
00687 this as standard behaviour for pointers would be useful in some algorithms.
00688 So even if this makes me look foolish, I would seem to be in distinguished 
00689 company.
00690 */
00691 
00692 

Generated on Thu Feb 19 22:04:36 2004 for libpqxx by doxygen 1.3.5