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     template<typename T> bool to(T &Obj) const                          //[t1]
00125     {
00126       if (is_null())
00127         return false;
00128 
00129       try
00130       {
00131         FromString(c_str(), Obj);
00132       }
00133       catch (const PGSTD::exception &e)
00134       {
00135         throw PGSTD::runtime_error("Error reading field " + 
00136                                    PGSTD::string(Name()) +
00137                                    ": " +
00138                                    e.what());
00139       }
00140       return true;
00141     }
00142 
00143 
00144 #ifdef NO_PARTIAL_CLASS_TEMPLATE_SPECIALISATION
00145 
00146     template<> bool to<PGSTD::string>(PGSTD::string &Obj) const;
00147 
00149 
00152     template<> bool to<const char *>(const char *&Obj) const;
00153 #endif
00154 
00155 
00157     template<typename T> bool to(T &Obj, const T &Default) const        //[t12]
00158     {
00159       const bool NotNull = to(Obj);
00160       if (!NotNull)
00161         Obj = Default;
00162       return NotNull;
00163     }
00164 
00165     bool is_null() const { return m_Home->GetIsNull(m_Index,m_Col); }   //[t12]
00166 
00167     size_type size() const { return m_Home->GetLength(m_Index,m_Col); } //[t11]
00168 
00169   private:
00170 
00171     Tuple::size_type m_Col;
00172   };
00173 
00174 
00176 
00180   class PQXX_LIBEXPORT const_iterator : 
00181     public PGSTD::iterator<PGSTD::random_access_iterator_tag, 
00182                          const Tuple,
00183                          Result::size_type>, 
00184     public Tuple
00185   {
00186   public:
00187     const_iterator() : Tuple(0,0) {}
00188 
00195     pointer operator->()  const { return this; }                        //[t12]
00196     reference operator*() const { return *operator->(); }               //[t12]
00197 
00198     const_iterator operator++(int);                                     //[t12]
00199     const_iterator &operator++() { ++m_Index; return *this; }           //[t1]
00200     const_iterator operator--(int);                                     //[t12]
00201     const_iterator &operator--() { --m_Index; return *this; }           //[t12]
00202 
00203     const_iterator &operator+=(difference_type i)                       //[t12]
00204         { m_Index+=i; return *this; }
00205     const_iterator &operator-=(difference_type i)                       //[t12]
00206         { m_Index-=i; return *this; }
00207 
00208     bool operator==(const const_iterator &i) const                      //[t12]
00209         {return m_Index==i.m_Index;}
00210     bool operator!=(const const_iterator &i) const                      //[t12]
00211         {return m_Index!=i.m_Index;}
00212     bool operator<(const const_iterator &i) const                       //[t12]
00213          {return m_Index<i.m_Index;}
00214     bool operator<=(const const_iterator &i) const                      //[t12]
00215         {return m_Index<=i.m_Index;}
00216     bool operator>(const const_iterator &i) const                       //[t12]
00217         {return m_Index>i.m_Index;}
00218     bool operator>=(const const_iterator &i) const                      //[t12]
00219         {return m_Index>=i.m_Index;}
00220 
00221     inline const_iterator operator+(difference_type o) const;           //[t12]
00222 
00223     friend const_iterator operator+(difference_type o, 
00224                                     const_iterator i);                  //[t12]
00225 
00226     inline const_iterator operator-(difference_type o) const;           //[t12]
00227 
00228     inline difference_type operator-(const_iterator i) const;           //[t12]
00229 
00230     Result::size_type num() const { return Row(); }                     //[t1]
00231 
00232   private:
00233     friend class Result;
00234     const_iterator(const Result *r, Result::size_type i) : Tuple(r, i) {}
00235   };
00236 
00237   const_iterator begin() const { return const_iterator(this, 0); }      //[t1]
00238   inline const_iterator end() const;                                    //[t1]
00239   // TODO: Reverse iterators
00240 
00241   size_type size() const { return m_Result ? PQntuples(m_Result) : 0; } //[t2]
00242   bool empty() const { return !m_Result || !PQntuples(m_Result); }      //[t11]
00243   size_type capacity() const { return size(); }                         //[t20]
00244 
00245   const Tuple operator[](size_type i) const { return Tuple(this, i); }  //[t2]
00246   const Tuple at(size_type) const;                                      //[t10]
00247 
00248   void clear() { LoseRef(); }                                           //[t20]
00249 
00250   Tuple::size_type Columns() const { return PQnfields(m_Result); }      //[t11]
00251 
00253   Tuple::size_type ColumnNumber(const char Name[]) const                //[t11]
00254         {return PQfnumber(m_Result,Name);}
00256   Tuple::size_type ColumnNumber(const std::string &Name) const          //[t11]
00257         {return ColumnNumber(Name.c_str());}
00258   const char *ColumnName(Tuple::size_type Number) const                 //[t11]
00259         {return PQfname(m_Result,Number);}
00260 
00262 
00263   Oid InsertedOid() const { return PQoidValue(m_Result); }              //[t13]
00264 
00266   /*** Returns zero for all other commands. */
00267   size_type AffectedRows() const;                                       //[t7]
00268 
00269 private:
00270   PGresult *m_Result;
00271   mutable int *m_Refcount;
00272 
00273   friend class Result::Field;
00274   const char *GetValue(size_type Row, Tuple::size_type Col) const;
00275   bool GetIsNull(size_type Row, Tuple::size_type Col) const;
00276   Field::size_type GetLength(size_type Row, Tuple::size_type Col) const;
00277 
00278   friend class Connection_base;
00279   explicit Result(PGresult *rhs) : m_Result(rhs), m_Refcount(0) {MakeRef(rhs);}
00280   Result &operator=(PGresult *);
00281   bool operator!() const throw () { return !m_Result; }
00282   operator bool() const throw () { return m_Result != 0; }
00283   void CheckStatus(const PGSTD::string &Query) const;
00284 
00285   friend class Cursor;
00286   const char *CmdStatus() const throw () { return PQcmdStatus(m_Result); }
00287 
00288 
00289   void MakeRef(PGresult *);
00290   void MakeRef(const Result &);
00291   void LoseRef() throw ();
00292 };
00293 
00294 
00296 
00303 class BinaryString : private PQAlloc<unsigned char>
00304 {
00305   typedef PQAlloc<unsigned char> super;
00306 public:
00307   typedef size_t size_type;
00308 
00310 
00313   explicit BinaryString(const Result::Field &F) :                       //[]
00314     super(),
00315     m_size(0)
00316   {
00317     super::operator=(PQunescapeBytea(reinterpret_cast<unsigned char *>(
00318             const_cast<char *>(F.c_str())), &m_size));
00319 
00320     // TODO: More useful error message!  Distinguish bad_alloc from parse error
00321     if (!c_ptr()) 
00322       throw std::runtime_error("Unable to read bytea field");
00323   }
00324 
00326   size_type size() const throw () { return m_size; }                    //[]
00327 
00329   const unsigned char *bytes() const throw () { return c_ptr(); }       //[]
00330 
00331 private:
00332   size_type m_size;
00333 };
00334 
00335 
00337 
00354 template<typename STREAM>
00355 inline STREAM &operator<<(STREAM &S, const pqxx::Result::Field &F)      //[t46]
00356 {
00357   S << F.c_str();
00358   return S;
00359 }
00360 
00361 
00362 
00363 inline Result::Field 
00364 Result::Tuple::operator[](Result::Tuple::size_type i) const 
00365 { 
00366   return Field(*this, i); 
00367 }
00368 
00369 inline Result::Tuple::size_type Result::Tuple::size() const 
00370 { 
00371   return m_Home->Columns(); 
00372 }
00373 
00374 inline const char *Result::Field::Name() const 
00375 { 
00376   return m_Home->ColumnName(m_Col); 
00377 }
00378 
00380 template<> 
00381 inline bool Result::Field::to<PGSTD::string>(PGSTD::string &Obj) const
00382 {
00383   if (is_null()) return false;
00384   Obj = c_str();
00385   return true;
00386 }
00387 
00389 
00392 template<> 
00393 inline bool Result::Field::to<const char *>(const char *&Obj) const
00394 {
00395   if (is_null()) return false;
00396   Obj = c_str();
00397   return true;
00398 }
00399 
00400 
00401 inline Result::const_iterator 
00402 Result::const_iterator::operator+(difference_type o) const
00403 {
00404   return const_iterator(m_Home, m_Index + o);
00405 }
00406 
00407 inline Result::const_iterator 
00408 operator+(Result::const_iterator::difference_type o, 
00409           Result::const_iterator i)
00410 {
00411   return i + o;
00412 }
00413 
00414 inline Result::const_iterator 
00415 Result::const_iterator::operator-(difference_type o) const
00416 {
00417   return const_iterator(m_Home, m_Index - o);
00418 }
00419 
00420 inline Result::const_iterator::difference_type 
00421 Result::const_iterator::operator-(const_iterator i) const
00422 { 
00423   return num()-i.num(); 
00424 }
00425 
00426 inline Result::const_iterator Result::end() const 
00427 { 
00428   return const_iterator(this, size()); 
00429 }
00430 
00431 } // namespace pqxx
00432 
00433 
00434 
00435 /* 
00436 [1] Scott Meyers, in one of his essential books, "Effective C++" and "More 
00437 Effective C++", points out that it is good style to have any class containing 
00438 a member of pointer type define its own destructor--just to show that it knows
00439 what it is doing.  This helps prevent nasty memory leak / double deletion bugs
00440 typically resulting from programmers' omission to deal with such issues in
00441 their destructors.
00442 
00443 The -Weffc++ option in gcc generates warnings for noncompliance with Scott's
00444 style guidelines, and hence necessitates the definition of this destructor,\
00445 trivial as it may be.
00446 
00447 [2] IIRC Alex Stepanov, the inventor of the STL, once remarked that having
00448 this as standard behaviour for pointers would be useful in some algorithms.
00449 So even if this makes me look foolish, I would seem to be in distinguished 
00450 company.
00451 */
00452 
00453 #endif
00454 

Generated on Sat May 10 18:53:39 2003 for libpqxx by doxygen1.3-rc3