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  * See COPYING for copyright license.  If you did not receive a file called
00013  * COPYING with this source code, please notify the distributor of this mistake,
00014  * or contact the author.
00015  *
00016  *-------------------------------------------------------------------------
00017  */
00018 #ifndef PQXX_RESULT_H
00019 #define PQXX_RESULT_H
00020 
00021 #include <stdexcept>
00022 
00023 #include "pqxx/util.h"
00024 
00025 /* Methods tested in eg. self-test program test1 are marked with "//[t1]"
00026  */
00027 
00028 
00029 // TODO: Support postgres arrays
00030 
00031 namespace pqxx
00032 {
00033 
00035 
00042 class PQXX_LIBEXPORT result
00043 {
00044 public:
00045   result() : m_Result(0), m_Refcount(0) {}                              //[t3]
00046   result(const result &rhs) :                                           //[t1]
00047           m_Result(0), m_Refcount(0) { MakeRef(rhs); }
00048   ~result() { LoseRef(); }                                              //[t1]
00049   
00050   result &operator=(const result &);                                    //[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) : m_Home(r), m_Index(i) {}
00071     ~tuple() {} // Yes Scott Meyers, you're absolutely right[1]
00072 
00073     inline field operator[](size_type) const;                           //[t1]
00074     field operator[](const char[]) const;                               //[t11]
00075     field operator[](const PGSTD::string &s) const                      //[t11]
00076         { return operator[](s.c_str()); }
00077     field at(size_type) const;                                          //[t10]
00078     field at(const char[]) const;                                       //[t11]
00079     field at(const PGSTD::string &s) const { return at(s.c_str()); }    //[t11]
00080 
00081     inline size_type size() const;                                      //[t11]
00082 
00083     result::size_type Row() const { return m_Index; }                   //[t11]
00084 
00085     size_type ColumnNumber(const PGSTD::string &ColName) const          //[t30]
00086         { return m_Home->ColumnNumber(ColName); }
00087 
00088     size_type ColumnNumber(const char ColName[]) const                  //[t30]
00089         { return m_Home->ColumnNumber(ColName); }
00090 
00091   protected:
00092     const result *m_Home;
00093     result::size_type m_Index;
00094 
00095     // Not allowed:
00096     tuple();
00097   };
00098 
00100   typedef tuple Tuple;
00101 
00102 
00104 
00107   class PQXX_LIBEXPORT field : private tuple
00108   {
00109   public:
00110     typedef size_t size_type;
00111 
00113 
00117     field(const tuple &R, tuple::size_type C) : tuple(R), m_Col(C) {}   //[t1]
00118 
00120 
00125     const char *c_str() const {return m_Home->GetValue(m_Index,m_Col);} //[t2]
00126 
00128     inline const char *Name() const;                                    //[t11]
00129 
00131 
00140     template<typename T> bool to(T &Obj) const                          //[t1]
00141     {
00142       if (is_null())
00143         return false;
00144 
00145       try
00146       {
00147         FromString(c_str(), Obj);
00148       }
00149       catch (const PGSTD::exception &e)
00150       {
00151         throw PGSTD::runtime_error("Error reading field " + 
00152                                    PGSTD::string(Name()) +
00153                                    ": " +
00154                                    e.what());
00155       }
00156       return true;
00157     }
00158 
00159 
00160 #ifdef NO_PARTIAL_CLASS_TEMPLATE_SPECIALISATION
00161 
00162     template<> bool to<PGSTD::string>(PGSTD::string &Obj) const;
00163 
00165 
00168     template<> bool to<const char *>(const char *&Obj) const;
00169 #endif
00170 
00171 
00173     template<typename T> bool to(T &Obj, const T &Default) const        //[t12]
00174     {
00175       const bool NotNull = to(Obj);
00176       if (!NotNull)
00177         Obj = Default;
00178       return NotNull;
00179     }
00180 
00182 
00185     template<typename T> T as(const T &Default) const                   //[t45]
00186     {
00187       T Obj;
00188       return to(Obj) ? Obj : Default;
00189     }
00190 
00191     bool is_null() const { return m_Home->GetIsNull(m_Index,m_Col); }   //[t12]
00192 
00193     size_type size() const { return m_Home->GetLength(m_Index,m_Col); } //[t11]
00194 
00195   private:
00196 
00197     tuple::size_type m_Col;
00198   };
00199 
00201   typedef field Field;
00202 
00204 
00208   class PQXX_LIBEXPORT const_iterator : 
00209     public PGSTD::iterator<PGSTD::random_access_iterator_tag, 
00210                          const tuple,
00211                          result::size_type>, 
00212     public tuple
00213   {
00214   public:
00215     const_iterator() : tuple(0,0) {}
00216 
00223     pointer operator->()  const { return this; }                        //[t12]
00224     reference operator*() const { return *operator->(); }               //[t12]
00225 
00226     const_iterator operator++(int);                                     //[t12]
00227     const_iterator &operator++() { ++m_Index; return *this; }           //[t1]
00228     const_iterator operator--(int);                                     //[t12]
00229     const_iterator &operator--() { --m_Index; return *this; }           //[t12]
00230 
00231     const_iterator &operator+=(difference_type i)                       //[t12]
00232         { m_Index+=i; return *this; }
00233     const_iterator &operator-=(difference_type i)                       //[t12]
00234         { m_Index-=i; return *this; }
00235 
00236     bool operator==(const const_iterator &i) const                      //[t12]
00237         {return m_Index==i.m_Index;}
00238     bool operator!=(const const_iterator &i) const                      //[t12]
00239         {return m_Index!=i.m_Index;}
00240     bool operator<(const const_iterator &i) const                       //[t12]
00241          {return m_Index<i.m_Index;}
00242     bool operator<=(const const_iterator &i) const                      //[t12]
00243         {return m_Index<=i.m_Index;}
00244     bool operator>(const const_iterator &i) const                       //[t12]
00245         {return m_Index>i.m_Index;}
00246     bool operator>=(const const_iterator &i) const                      //[t12]
00247         {return m_Index>=i.m_Index;}
00248 
00249     inline const_iterator operator+(difference_type o) const;           //[t12]
00250 
00251     friend const_iterator operator+(difference_type o, 
00252                                     const_iterator i);                  //[t12]
00253 
00254     inline const_iterator operator-(difference_type o) const;           //[t12]
00255 
00256     inline difference_type operator-(const_iterator i) const;           //[t12]
00257 
00258     result::size_type num() const { return Row(); }                     //[t1]
00259 
00260   private:
00261     friend class result;
00262     const_iterator(const result *r, result::size_type i) : tuple(r, i) {}
00263   };
00264 
00265   const_iterator begin() const { return const_iterator(this, 0); }      //[t1]
00266   inline const_iterator end() const;                                    //[t1]
00267   // TODO: Reverse iterators
00268 
00269   size_type size() const { return m_Result ? PQntuples(m_Result) : 0; } //[t2]
00270   bool empty() const { return !m_Result || !PQntuples(m_Result); }      //[t11]
00271   size_type capacity() const { return size(); }                         //[t20]
00272 
00273   const tuple operator[](size_type i) const { return tuple(this, i); }  //[t2]
00274   const tuple at(size_type) const;                                      //[t10]
00275 
00276   void clear() { LoseRef(); }                                           //[t20]
00277 
00278   tuple::size_type Columns() const { return PQnfields(m_Result); }      //[t11]
00279 
00281   tuple::size_type ColumnNumber(const char Name[]) const                //[t11]
00282         {return PQfnumber(m_Result,Name);}
00284   tuple::size_type ColumnNumber(const std::string &Name) const          //[t11]
00285         {return ColumnNumber(Name.c_str());}
00286   const char *ColumnName(tuple::size_type Number) const                 //[t11]
00287         {return PQfname(m_Result,Number);}
00288 
00290 
00292   oid InsertedOid() const { return PQoidValue(m_Result); }              //[t13]
00293 
00295   /*** Returns zero for all other commands. */
00296   size_type AffectedRows() const;                                       //[t7]
00297 
00298 private:
00299   PGresult *m_Result;
00300   mutable int *m_Refcount;
00301 
00302   friend class result::field;
00303   const char *GetValue(size_type Row, tuple::size_type Col) const;
00304   bool GetIsNull(size_type Row, tuple::size_type Col) const;
00305   field::size_type GetLength(size_type Row, tuple::size_type Col) const;
00306 
00307   friend class connection_base;
00308   explicit result(PGresult *rhs) : m_Result(rhs), m_Refcount(0) {MakeRef(rhs);}
00309   result &operator=(PGresult *);
00310   bool operator!() const throw () { return !m_Result; }
00311   operator bool() const throw () { return m_Result != 0; }
00312   void CheckStatus(const PGSTD::string &Query) const;
00313 
00314   friend class Cursor;
00315   const char *CmdStatus() const throw () { return PQcmdStatus(m_Result); }
00316 
00317 
00318   void MakeRef(PGresult *);
00319   void MakeRef(const result &);
00320   void LoseRef() throw ();
00321 };
00322 
00323 
00325 
00332 class PQXX_LIBEXPORT binarystring : private PQAlloc<unsigned char>
00333 {
00334   typedef PQAlloc<unsigned char> super;
00335 public:
00336   typedef size_t size_type;
00337 
00339 
00342   explicit binarystring(const result::field &F) :                       //[]
00343     super(),
00344     m_size(0)
00345   {
00346     super::operator=(PQunescapeBytea(reinterpret_cast<unsigned char *>(
00347             const_cast<char *>(F.c_str())), &m_size));
00348 
00349     // TODO: More useful error message!  Distinguish bad_alloc from parse error
00350     if (!c_ptr()) 
00351       throw std::runtime_error("Unable to read bytea field");
00352   }
00353 
00355   size_type size() const throw () { return m_size; }                    //[]
00356 
00358   const unsigned char *bytes() const throw () { return c_ptr(); }       //[]
00359 
00360 private:
00361   size_type m_size;
00362 };
00363 
00364 
00366 typedef binarystring BinaryString;
00367 
00369 typedef result Result;
00370 
00371 
00373 
00390 template<typename STREAM>
00391 inline STREAM &operator<<(STREAM &S, const pqxx::result::field &F)      //[t46]
00392 {
00393   S << F.c_str();
00394   return S;
00395 }
00396 
00397 
00398 
00399 inline result::field 
00400 result::tuple::operator[](result::tuple::size_type i) const 
00401 { 
00402   return field(*this, i); 
00403 }
00404 
00405 inline result::tuple::size_type result::tuple::size() const 
00406 { 
00407   return m_Home->Columns(); 
00408 }
00409 
00410 inline const char *result::field::Name() const 
00411 { 
00412   return m_Home->ColumnName(m_Col); 
00413 }
00414 
00416 template<> 
00417 inline bool result::field::to<PGSTD::string>(PGSTD::string &Obj) const
00418 {
00419   if (is_null()) return false;
00420   Obj = c_str();
00421   return true;
00422 }
00423 
00425 
00428 template<> 
00429 inline bool result::field::to<const char *>(const char *&Obj) const
00430 {
00431   if (is_null()) return false;
00432   Obj = c_str();
00433   return true;
00434 }
00435 
00436 
00437 inline result::const_iterator 
00438 result::const_iterator::operator+(difference_type o) const
00439 {
00440   return const_iterator(m_Home, m_Index + o);
00441 }
00442 
00443 inline result::const_iterator 
00444 operator+(result::const_iterator::difference_type o, 
00445           result::const_iterator i)
00446 {
00447   return i + o;
00448 }
00449 
00450 inline result::const_iterator 
00451 result::const_iterator::operator-(difference_type o) const
00452 {
00453   return const_iterator(m_Home, m_Index - o);
00454 }
00455 
00456 inline result::const_iterator::difference_type 
00457 result::const_iterator::operator-(const_iterator i) const
00458 { 
00459   return num()-i.num(); 
00460 }
00461 
00462 inline result::const_iterator result::end() const 
00463 { 
00464   return const_iterator(this, size()); 
00465 }
00466 
00467 } // namespace pqxx
00468 
00469 
00470 
00471 /* 
00472 [1] Scott Meyers, in one of his essential books, "Effective C++" and "More 
00473 Effective C++", points out that it is good style to have any class containing 
00474 a member of pointer type define its own destructor--just to show that it knows
00475 what it is doing.  This helps prevent nasty memory leak / double deletion bugs
00476 typically resulting from programmers' omission to deal with such issues in
00477 their destructors.
00478 
00479 The -Weffc++ option in gcc generates warnings for noncompliance with Scott's
00480 style guidelines, and hence necessitates the definition of this destructor,\
00481 trivial as it may be.
00482 
00483 [2] IIRC Alex Stepanov, the inventor of the STL, once remarked that having
00484 this as standard behaviour for pointers would be useful in some algorithms.
00485 So even if this makes me look foolish, I would seem to be in distinguished 
00486 company.
00487 */
00488 
00489 #endif
00490 

Generated on Sat Jun 7 00:49:34 2003 for libpqxx by doxygen1.3-rc3