Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

result.h

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  *   FILE
00004  *      pqxx/result.h
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  *
00010  * Copyright (c) 2001-2003, Jeroen T. Vermeulen <jtv@xs4all.nl>
00011  *
00012  *-------------------------------------------------------------------------
00013  */
00014 #ifndef PQXX_RESULT_H
00015 #define PQXX_RESULT_H
00016 
00017 #include <stdexcept>
00018 
00019 #include "pqxx/util.h"
00020 
00021 /* Methods tested in eg. self-test program test1 are marked with "//[t1]"
00022  */
00023 
00024 
00025 // TODO: Support postgres arrays
00026 
00027 namespace pqxx
00028 {
00029 
00031 
00038 class PQXX_LIBEXPORT Result
00039 {
00040 public:
00041   Result() : m_Result(0), m_Refcount(0) {}                              //[t3]
00042   Result(const Result &rhs) :                                           //[t1]
00043           m_Result(0), m_Refcount(0) { MakeRef(rhs); }
00044   ~Result() { LoseRef(); }                                              //[t1]
00045   
00046   Result &operator=(const Result &);                                    //[t10]
00047 
00048   typedef Result_size_type size_type;
00049   class Field;
00050 
00051   // TODO: Field iterators
00052  
00054 
00062   class PQXX_LIBEXPORT Tuple
00063   {
00064   public:
00065     typedef Tuple_size_type size_type;
00066     Tuple(const Result *r, Result::size_type i) : m_Home(r), m_Index(i) {}
00067     ~Tuple() {} // Yes Scott Meyers, you're absolutely right[1]
00068 
00069     inline Field operator[](size_type) const;                           //[t1]
00070     Field operator[](const char[]) const;                               //[t11]
00071     Field operator[](const PGSTD::string &s) const                      //[t11]
00072         { return operator[](s.c_str()); }
00073     Field at(size_type) const;                                          //[t10]
00074     Field at(const char[]) const;                                       //[t11]
00075     Field at(const PGSTD::string &s) const { return at(s.c_str()); }    //[t11]
00076 
00077     inline size_type size() const;                                      //[t11]
00078 
00079     Result::size_type Row() const { return m_Index; }                   //[t11]
00080 
00081     size_type ColumnNumber(const PGSTD::string &ColName) const          //[t30]
00082         { return m_Home->ColumnNumber(ColName); }
00083 
00084     size_type ColumnNumber(const char ColName[]) const                  //[t30]
00085         { return m_Home->ColumnNumber(ColName); }
00086 
00087   protected:
00088     const Result *m_Home;
00089     Result::size_type m_Index;
00090 
00091     // Not allowed:
00092     Tuple();
00093   };
00094 
00095 
00097 
00100   class PQXX_LIBEXPORT Field : private Tuple
00101   {
00102   public:
00103     typedef size_t size_type;
00104 
00106 
00110     Field(const Tuple &R, Tuple::size_type C) : Tuple(R), m_Col(C) {}   //[t1]
00111 
00113 
00118     const char *c_str() const {return m_Home->GetValue(m_Index,m_Col);} //[t2]
00119 
00121     inline const char *Name() const;                                    //[t11]
00122 
00124 
00132     template<typename T> bool to(T &Obj) const                          //[t1]
00133     {
00134       if (is_null())
00135         return false;
00136 
00137       try
00138       {
00139         FromString(c_str(), Obj);
00140       }
00141       catch (const PGSTD::exception &e)
00142       {
00143         throw PGSTD::runtime_error("Error reading field " + 
00144                                    PGSTD::string(Name()) +
00145                                    ": " +
00146                                    e.what());
00147       }
00148       return true;
00149     }
00150 
00151 
00152 #ifdef NO_PARTIAL_CLASS_TEMPLATE_SPECIALISATION
00153 
00154     template<> bool to<PGSTD::string>(PGSTD::string &Obj) const;
00155 
00157 
00160     template<> bool to<const char *>(const char *&Obj) const;
00161 #endif
00162 
00163 
00165     template<typename T> bool to(T &Obj, const T &Default) const        //[t12]
00166     {
00167       const bool NotNull = to(Obj);
00168       if (!NotNull)
00169         Obj = Default;
00170       return NotNull;
00171     }
00172 
00174 
00177     template<typename T> T as(const T &Default) const                   //[t45]
00178     {
00179       T Obj;
00180       return to(Obj) ? Obj : Default;
00181     }
00182 
00183     bool is_null() const { return m_Home->GetIsNull(m_Index,m_Col); }   //[t12]
00184 
00185     size_type size() const { return m_Home->GetLength(m_Index,m_Col); } //[t11]
00186 
00187   private:
00188 
00189     Tuple::size_type m_Col;
00190   };
00191 
00192 
00194 
00198   class PQXX_LIBEXPORT const_iterator : 
00199     public PGSTD::iterator<PGSTD::random_access_iterator_tag, 
00200                          const Tuple,
00201                          Result::size_type>, 
00202     public Tuple
00203   {
00204   public:
00205     const_iterator() : Tuple(0,0) {}
00206 
00213     pointer operator->()  const { return this; }                        //[t12]
00214     reference operator*() const { return *operator->(); }               //[t12]
00215 
00216     const_iterator operator++(int);                                     //[t12]
00217     const_iterator &operator++() { ++m_Index; return *this; }           //[t1]
00218     const_iterator operator--(int);                                     //[t12]
00219     const_iterator &operator--() { --m_Index; return *this; }           //[t12]
00220 
00221     const_iterator &operator+=(difference_type i)                       //[t12]
00222         { m_Index+=i; return *this; }
00223     const_iterator &operator-=(difference_type i)                       //[t12]
00224         { m_Index-=i; return *this; }
00225 
00226     bool operator==(const const_iterator &i) const                      //[t12]
00227         {return m_Index==i.m_Index;}
00228     bool operator!=(const const_iterator &i) const                      //[t12]
00229         {return m_Index!=i.m_Index;}
00230     bool operator<(const const_iterator &i) const                       //[t12]
00231          {return m_Index<i.m_Index;}
00232     bool operator<=(const const_iterator &i) const                      //[t12]
00233         {return m_Index<=i.m_Index;}
00234     bool operator>(const const_iterator &i) const                       //[t12]
00235         {return m_Index>i.m_Index;}
00236     bool operator>=(const const_iterator &i) const                      //[t12]
00237         {return m_Index>=i.m_Index;}
00238 
00239     inline const_iterator operator+(difference_type o) const;           //[t12]
00240 
00241     friend const_iterator operator+(difference_type o, 
00242                                     const_iterator i);                  //[t12]
00243 
00244     inline const_iterator operator-(difference_type o) const;           //[t12]
00245 
00246     inline difference_type operator-(const_iterator i) const;           //[t12]
00247 
00248     Result::size_type num() const { return Row(); }                     //[t1]
00249 
00250   private:
00251     friend class Result;
00252     const_iterator(const Result *r, Result::size_type i) : Tuple(r, i) {}
00253   };
00254 
00255   const_iterator begin() const { return const_iterator(this, 0); }      //[t1]
00256   inline const_iterator end() const;                                    //[t1]
00257   // TODO: Reverse iterators
00258 
00259   size_type size() const { return m_Result ? PQntuples(m_Result) : 0; } //[t2]
00260   bool empty() const { return !m_Result || !PQntuples(m_Result); }      //[t11]
00261   size_type capacity() const { return size(); }                         //[t20]
00262 
00263   const Tuple operator[](size_type i) const { return Tuple(this, i); }  //[t2]
00264   const Tuple at(size_type) const;                                      //[t10]
00265 
00266   void clear() { LoseRef(); }                                           //[t20]
00267 
00268   Tuple::size_type Columns() const { return PQnfields(m_Result); }      //[t11]
00269 
00271   Tuple::size_type ColumnNumber(const char Name[]) const                //[t11]
00272         {return PQfnumber(m_Result,Name);}
00274   Tuple::size_type ColumnNumber(const std::string &Name) const          //[t11]
00275         {return ColumnNumber(Name.c_str());}
00276   const char *ColumnName(Tuple::size_type Number) const                 //[t11]
00277         {return PQfname(m_Result,Number);}
00278 
00280 
00281   Oid InsertedOid() const { return PQoidValue(m_Result); }              //[t13]
00282 
00284   /*** Returns zero for all other commands. */
00285   size_type AffectedRows() const;                                       //[t7]
00286 
00287 private:
00288   PGresult *m_Result;
00289   mutable int *m_Refcount;
00290 
00291   friend class Result::Field;
00292   const char *GetValue(size_type Row, Tuple::size_type Col) const;
00293   bool GetIsNull(size_type Row, Tuple::size_type Col) const;
00294   Field::size_type GetLength(size_type Row, Tuple::size_type Col) const;
00295 
00296   friend class Connection_base;
00297   explicit Result(PGresult *rhs) : m_Result(rhs), m_Refcount(0) {MakeRef(rhs);}
00298   Result &operator=(PGresult *);
00299   bool operator!() const throw () { return !m_Result; }
00300   operator bool() const throw () { return m_Result != 0; }
00301   void CheckStatus(const PGSTD::string &Query) const;
00302 
00303   friend class Cursor;
00304   const char *CmdStatus() const throw () { return PQcmdStatus(m_Result); }
00305 
00306 
00307   void MakeRef(PGresult *);
00308   void MakeRef(const Result &);
00309   void LoseRef() throw ();
00310 };
00311 
00312 
00314 
00321 class BinaryString : private PQAlloc<unsigned char>
00322 {
00323   typedef PQAlloc<unsigned char> super;
00324 public:
00325   typedef size_t size_type;
00326 
00328 
00331   explicit BinaryString(const Result::Field &F) :                       //[]
00332     super(),
00333     m_size(0)
00334   {
00335     super::operator=(PQunescapeBytea(reinterpret_cast<unsigned char *>(
00336             const_cast<char *>(F.c_str())), &m_size));
00337 
00338     // TODO: More useful error message!  Distinguish bad_alloc from parse error
00339     if (!c_ptr()) 
00340       throw std::runtime_error("Unable to read bytea field");
00341   }
00342 
00344   size_type size() const throw () { return m_size; }                    //[]
00345 
00347   const unsigned char *bytes() const throw () { return c_ptr(); }       //[]
00348 
00349 private:
00350   size_type m_size;
00351 };
00352 
00353 
00355 
00372 template<typename STREAM>
00373 inline STREAM &operator<<(STREAM &S, const pqxx::Result::Field &F)      //[t46]
00374 {
00375   S << F.c_str();
00376   return S;
00377 }
00378 
00379 
00380 
00381 inline Result::Field 
00382 Result::Tuple::operator[](Result::Tuple::size_type i) const 
00383 { 
00384   return Field(*this, i); 
00385 }
00386 
00387 inline Result::Tuple::size_type Result::Tuple::size() const 
00388 { 
00389   return m_Home->Columns(); 
00390 }
00391 
00392 inline const char *Result::Field::Name() const 
00393 { 
00394   return m_Home->ColumnName(m_Col); 
00395 }
00396 
00398 template<> 
00399 inline bool Result::Field::to<PGSTD::string>(PGSTD::string &Obj) const
00400 {
00401   if (is_null()) return false;
00402   Obj = c_str();
00403   return true;
00404 }
00405 
00407 
00410 template<> 
00411 inline bool Result::Field::to<const char *>(const char *&Obj) const
00412 {
00413   if (is_null()) return false;
00414   Obj = c_str();
00415   return true;
00416 }
00417 
00418 
00419 inline Result::const_iterator 
00420 Result::const_iterator::operator+(difference_type o) const
00421 {
00422   return const_iterator(m_Home, m_Index + o);
00423 }
00424 
00425 inline Result::const_iterator 
00426 operator+(Result::const_iterator::difference_type o, 
00427           Result::const_iterator i)
00428 {
00429   return i + o;
00430 }
00431 
00432 inline Result::const_iterator 
00433 Result::const_iterator::operator-(difference_type o) const
00434 {
00435   return const_iterator(m_Home, m_Index - o);
00436 }
00437 
00438 inline Result::const_iterator::difference_type 
00439 Result::const_iterator::operator-(const_iterator i) const
00440 { 
00441   return num()-i.num(); 
00442 }
00443 
00444 inline Result::const_iterator Result::end() const 
00445 { 
00446   return const_iterator(this, size()); 
00447 }
00448 
00449 } // namespace pqxx
00450 
00451 
00452 
00453 /* 
00454 [1] Scott Meyers, in one of his essential books, "Effective C++" and "More 
00455 Effective C++", points out that it is good style to have any class containing 
00456 a member of pointer type define its own destructor--just to show that it knows
00457 what it is doing.  This helps prevent nasty memory leak / double deletion bugs
00458 typically resulting from programmers' omission to deal with such issues in
00459 their destructors.
00460 
00461 The -Weffc++ option in gcc generates warnings for noncompliance with Scott's
00462 style guidelines, and hence necessitates the definition of this destructor,\
00463 trivial as it may be.
00464 
00465 [2] IIRC Alex Stepanov, the inventor of the STL, once remarked that having
00466 this as standard behaviour for pointers would be useful in some algorithms.
00467 So even if this makes me look foolish, I would seem to be in distinguished 
00468 company.
00469 */
00470 
00471 #endif
00472 

Generated on Sat May 24 02:03:12 2003 for libpqxx by doxygen1.3-rc3