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         from_string(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   void swap(result &other) throw ();                                    //[t77]
00337 
00338   const tuple operator[](size_type i) const throw ()                    //[t2]
00339         { return tuple(this, i); }
00340   const tuple at(size_type) const throw (PGSTD::out_of_range);          //[t10]
00341 
00342   void clear() throw () { LoseRef(); }                                  //[t20]
00343 
00345   tuple::size_type columns() const throw ()                             //[t11]
00346         { return PQnfields(m_Result); }
00347 
00349   tuple::size_type column_number(const char ColName[]) const;           //[t11]
00350 
00352   tuple::size_type column_number(const PGSTD::string &Name) const       //[t11]
00353         {return column_number(Name.c_str());}
00354 
00356   const char *column_name(tuple::size_type Number) const;               //[t11]
00357 
00359   inline oid column_type(tuple::size_type ColNum) const;                //[t7]
00360 
00362   oid column_type(const PGSTD::string &ColName) const                   //[t7]
00363         { return column_type(column_number(ColName)); }
00364 
00366   oid column_type(const char ColName[]) const                           //[t7]
00367         { return column_type(column_number(ColName)); }
00368 
00369 #ifdef PQXX_HAVE_PQFTABLE
00370 
00371   oid column_table(tuple::size_type ColNum) const;                      //[t2]
00372 
00374   oid column_table(const PGSTD::string &ColName) const                  //[t2]
00375         { return column_table(column_number(ColName)); }
00376 #endif
00377 
00378 
00380 
00382   oid inserted_oid() const { return PQoidValue(m_Result); }             //[t13]
00383 
00384 
00386   /*** Returns zero for all other commands. */
00387   size_type affected_rows() const;                                      //[t7]
00388 
00389 
00390 #ifdef PQXX_DEPRECATED_HEADERS
00391 
00392   typedef tuple Tuple;
00394   typedef field Field;
00396   oid InsertedOid() const { return inserted_oid(); }
00398   size_type AffectedRows() const { return affected_rows(); }
00400   tuple::size_type Columns() const { return columns(); }
00402   tuple::size_type ColumnNumber(const char Name[]) const
00403         {return PQfnumber(m_Result,Name);}
00405   tuple::size_type ColumnNumber(const PGSTD::string &Name) const
00406         {return ColumnNumber(Name.c_str());}
00408   const char *ColumnName(tuple::size_type Number) const
00409         {return PQfname(m_Result,Number);}
00410 #endif
00411 
00412 
00413 private:
00414   PGresult *m_Result;
00415   mutable int *m_Refcount;
00416 
00417   friend class result::field;
00418   const char *GetValue(size_type Row, tuple::size_type Col) const;
00419   bool GetIsNull(size_type Row, tuple::size_type Col) const;
00420   field::size_type GetLength(size_type Row, tuple::size_type Col) const;
00421 
00422   friend class connection_base;
00423   explicit result(PGresult *rhs) : m_Result(rhs), m_Refcount(0) {MakeRef(rhs);}
00424   result &operator=(PGresult *);
00425   bool operator!() const throw () { return !m_Result; }
00426   operator bool() const throw () { return m_Result != 0; }
00427   friend class pipeline;
00428   void CheckStatus(const PGSTD::string &Query) const;
00429   void CheckStatus(const char Query[]) const;
00430   PGSTD::string StatusError() const;
00431 
00432   friend class Cursor;
00433   const char *CmdStatus() const throw () { return PQcmdStatus(m_Result); }
00434 
00435 
00436   void MakeRef(PGresult *);
00437   void MakeRef(const result &) throw ();
00438   void LoseRef() throw ();
00439 };
00440 
00441 
00443 
00460 template<typename STREAM>
00461 inline STREAM &operator<<(STREAM &S, const pqxx::result::field &F)      //[t46]
00462 {
00463   S.write(F.c_str(), F.size());
00464   return S;
00465 }
00466 
00467 
00469 template<typename T>
00470 inline void from_string(const result::field &F, T &Obj)                 //[t46]
00471         { from_string(F.c_str(), Obj); }
00472 
00474 template<>
00475 inline PGSTD::string to_string(const result::field &Obj)                //[t74]
00476         { return to_string(Obj.c_str()); }
00477 
00478 inline result::field 
00479 result::tuple::operator[](result::tuple::size_type i) const  throw ()
00480 { 
00481   return field(*this, i); 
00482 }
00483 
00484 inline result::tuple::size_type result::tuple::size() const throw ()
00485 { 
00486   return m_Home->columns(); 
00487 }
00488 
00489 inline const char *result::field::name() const 
00490 { 
00491   return m_Home->column_name(m_Col); 
00492 }
00493 
00495 template<> 
00496 inline bool result::field::to<PGSTD::string>(PGSTD::string &Obj) const
00497 {
00498   if (is_null()) return false;
00499   Obj = c_str();
00500   return true;
00501 }
00502 
00504 
00507 template<> 
00508 inline bool result::field::to<const char *>(const char *&Obj) const
00509 {
00510   if (is_null()) return false;
00511   Obj = c_str();
00512   return true;
00513 }
00514 
00515 
00516 inline result::const_iterator 
00517 result::const_iterator::operator+(difference_type o) const
00518 {
00519   return const_iterator(m_Home, m_Index + o);
00520 }
00521 
00522 inline result::const_iterator 
00523 operator+(result::const_iterator::difference_type o, 
00524           result::const_iterator i)
00525 {
00526   return i + o;
00527 }
00528 
00529 inline result::const_iterator 
00530 result::const_iterator::operator-(difference_type o) const
00531 {
00532   return const_iterator(m_Home, m_Index - o);
00533 }
00534 
00535 inline result::const_iterator::difference_type 
00536 result::const_iterator::operator-(const_iterator i) const
00537 { 
00538   return num()-i.num(); 
00539 }
00540 
00541 inline result::const_iterator result::end() const 
00542 { 
00543   return const_iterator(this, size()); 
00544 }
00545 
00546 inline oid result::column_type(tuple::size_type ColNum) const
00547 {
00548   const oid T = PQftype(m_Result, ColNum);
00549   if (T == oid_none)
00550     throw PGSTD::invalid_argument(
00551                 "Attempt to retrieve type of nonexistant column " +
00552                 to_string(ColNum) + " "
00553                 "of query result");
00554   return T;
00555 }
00556 
00557 
00558 #ifdef PQXX_HAVE_PQFTABLE
00559 inline oid result::column_table(tuple::size_type ColNum) const
00560 {
00561   const oid T = PQftable(m_Result, ColNum);
00562 
00563   /* If we get InvalidOid, it may be because the column is computed, or because
00564    * we got an invalid row number.
00565    */
00566   // TODO: Skip this if we first computed the column name ourselves
00567   if ((T == InvalidOid) &&
00568       ((ColNum < 0) || (ColNum >= columns())))
00569     throw PGSTD::invalid_argument("Attempt to retrieve table ID for column " +
00570                                   to_string(ColNum) + " "
00571                                   "out of " + to_string(columns()));
00572   return T;
00573 }
00574 #endif
00575 
00576 
00577 template<typename CHAR=char, typename TRAITS=PGSTD::char_traits<CHAR> >
00578   class field_streambuf :
00579 #ifdef PQXX_HAVE_STREAMBUF
00580   public PGSTD::basic_streambuf<CHAR, TRAITS>
00581 #else
00582   public PGSTD::streambuf
00583 #endif
00584 {
00585   typedef long size_type;
00586 public:
00587   typedef CHAR char_type;
00588   typedef TRAITS traits_type;
00589   typedef typename traits_type::int_type int_type;
00590 #ifdef PQXX_HAVE_STREAMBUF
00591   typedef typename traits_type::pos_type pos_type;
00592   typedef typename traits_type::off_type off_type;
00593 #else
00594   typedef streamoff off_type;
00595   typedef streampos pos_type;
00596 #endif
00597   typedef PGSTD::ios::openmode openmode;
00598   typedef PGSTD::ios::seekdir seekdir;
00599 
00600   explicit field_streambuf(const result::field &F) :                    //[t74]
00601     m_Field(F)
00602   {
00603     initialize();
00604   }
00605 
00606 #ifdef PQXX_HAVE_STREAMBUF
00607 protected:
00608 #endif
00609   virtual int sync() { return traits_type::eof(); }
00610 
00611 protected:
00612   virtual pos_type seekoff(off_type, seekdir, openmode)
00613   {
00614     return traits_type::eof();
00615   }
00616 
00617   virtual pos_type seekpos(pos_type, openmode) {return traits_type::eof();}
00618 
00619   virtual int_type overflow(int_type) { return traits_type::eof(); }
00620 
00621   // TODO: This isn't good enough with g++ 2.95--it crashes somewhere near here!
00622   virtual int_type underflow() { return initialize(); }
00623 
00624 private:
00625   const result::field &m_Field;
00626 
00627   int_type initialize() throw ()
00628   {
00629     char_type *G = 
00630       reinterpret_cast<char_type *>(const_cast<char *>(m_Field.c_str()));
00631     setg(G, G, G + m_Field.size());
00632     return m_Field.size();
00633   }
00634 };
00635 
00636 
00638 
00652 template<typename CHAR=char, typename TRAITS=PGSTD::char_traits<CHAR> >
00653   class basic_fieldstream :
00654 #ifdef PQXX_HAVE_STREAMBUF
00655     public PGSTD::basic_istream<CHAR, TRAITS>
00656 #else
00657     public PGSTD::istream
00658 #endif
00659 {
00660 #ifdef PQXX_HAVE_STREAMBUF
00661   typedef PGSTD::basic_istream<CHAR, TRAITS> super;
00662 #else
00663   typedef PGSTD::istream super;
00664 #endif
00665 
00666 public:
00667   typedef CHAR char_type;
00668   typedef TRAITS traits_type;
00669   typedef typename traits_type::int_type int_type;
00670   typedef typename traits_type::pos_type pos_type;
00671   typedef typename traits_type::off_type off_type;
00672 
00673   basic_fieldstream(const result::field &F) : super(&m_Buf), m_Buf(F) { }
00674 
00675 private:
00676   field_streambuf<CHAR, TRAITS> m_Buf;
00677 };
00678 
00679 typedef basic_fieldstream<char> fieldstream;
00680 
00681 } // namespace pqxx
00682 
00683 
00684 
00685 /* 
00686 [1] Scott Meyers, in one of his essential books, "Effective C++" and "More 
00687 Effective C++", points out that it is good style to have any class containing 
00688 a member of pointer type define its own destructor--just to show that it knows
00689 what it is doing.  This helps prevent nasty memory leak / double deletion bugs
00690 typically resulting from programmers' omission to deal with such issues in
00691 their destructors.
00692 
00693 The -Weffc++ option in gcc generates warnings for noncompliance with Scott's
00694 style guidelines, and hence necessitates the definition of this destructor,\
00695 trivial as it may be.
00696 
00697 [2] IIRC Alex Stepanov, the inventor of the STL, once remarked that having
00698 this as standard behaviour for pointers would be useful in some algorithms.
00699 So even if this makes me look foolish, I would seem to be in distinguished 
00700 company.
00701 */
00702 
00703 

Generated on Thu Mar 18 21:25:48 2004 for libpqxx by doxygen 1.3.6-20040222