Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members

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-2003, 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 test1 are marked with "//[t1]"
00024  */
00025 
00026 
00027 // TODO: Support postgres arrays
00028 
00029 namespace pqxx
00030 {
00031 
00033 
00040 class PQXX_LIBEXPORT result
00041 {
00042 public:
00043   result() : m_Result(0), m_Refcount(0) {}                              //[t3]
00044   result(const result &rhs) :                                           //[t1]
00045           m_Result(0), m_Refcount(0) { MakeRef(rhs); }
00046   ~result() { LoseRef(); }                                              //[t1]
00047   
00048   result &operator=(const result &);                                    //[t10]
00049 
00050   typedef result_size_type size_type;
00051   class field;
00052 
00053   // TODO: Field iterators
00054  
00056 
00064   class PQXX_LIBEXPORT tuple
00065   {
00066   public:
00067     typedef tuple_size_type size_type;
00068     tuple(const result *r, result::size_type i) : m_Home(r), m_Index(i) {}
00069     ~tuple() {} // Yes Scott Meyers, you're absolutely right[1]
00070 
00071     inline field operator[](size_type) const;                           //[t1]
00072     field operator[](const char[]) const;                               //[t11]
00073     field operator[](const PGSTD::string &s) const                      //[t11]
00074         { return operator[](s.c_str()); }
00075     field at(size_type) const;                                          //[t10]
00076     field at(const char[]) const;                                       //[t11]
00077     field at(const PGSTD::string &s) const { return at(s.c_str()); }    //[t11]
00078 
00079     inline size_type size() const;                                      //[t11]
00080 
00081 #ifdef PQXX_DEPRECATED_HEADERS
00082 
00083     result::size_type Row() const { return rownumber(); }
00084 
00086     size_type ColumnNumber(const PGSTD::string &ColName) const 
00087         { return m_Home->ColumnNumber(ColName); }
00088 
00090     size_type ColumnNumber(const char ColName[]) const 
00091         { return m_Home->ColumnNumber(ColName); }
00092 #endif
00093 
00094     result::size_type rownumber() const { return m_Index; }             //[t11]
00095 
00097     size_type column_number(const PGSTD::string &ColName) const         //[t30]
00098         { return m_Home->column_number(ColName); }
00099 
00101     size_type column_number(const char ColName[]) const                 //[t30]
00102         { return m_Home->column_number(ColName); }
00103 
00105     oid column_type(size_type ColNum) const                             //[t7]
00106         { return m_Home->column_type(ColNum); }
00107 
00109     oid column_type(const PGSTD::string &ColName) const                 //[t7]
00110         { return column_type(column_number(ColName)); }
00111 
00113     oid column_type(const char ColName[]) const                         //[t7]
00114         { return column_type(column_number(ColName)); }
00115 
00116 #ifdef PQXX_HAVE_PQFTABLE
00117     oid column_table(size_type ColNum) const                            //[t2]
00118         { return m_Home->column_table(ColNum); }
00119     oid column_table(const PGSTD::string &ColName) const                //[t2]
00120         { return column_table(column_number(ColName)); }
00121 #endif
00122 
00123   protected:
00124     const result *m_Home;
00125     result::size_type m_Index;
00126 
00127     // Not allowed:
00128     tuple();
00129   };
00130 
00131 #ifdef PQXX_DEPRECATED_HEADERS
00132 
00133   typedef tuple Tuple;
00134 #endif
00135 
00136 
00138 
00141   class PQXX_LIBEXPORT field : private tuple
00142   {
00143   public:
00144     typedef size_t size_type;
00145 
00147 
00151     field(const tuple &R, tuple::size_type C) : tuple(R), m_Col(C) {}   //[t1]
00152 
00154 
00159     const char *c_str() const {return m_Home->GetValue(m_Index,m_Col);} //[t2]
00160 
00161 #ifdef PQXX_DEPRECATED_HEADERS
00162 
00163     const char *Name() const {return name();}
00164 #endif
00165 
00167     inline const char *name() const;                                    //[t11]
00168 
00170     oid type() const                                                    //[t7]
00171         { return m_Home->column_type(m_Col); }
00172 
00173 #ifdef PQXX_HAVE_PQFTABLE
00174 
00175 
00177     oid table() const { return m_Home->column_table(m_Col); }           //[t2]
00178 #endif
00179 
00181 
00190     template<typename T> bool to(T &Obj) const                          //[t3]
00191     {
00192       if (is_null())
00193         return false;
00194 
00195       try
00196       {
00197         FromString(c_str(), Obj);
00198       }
00199       catch (const PGSTD::exception &e)
00200       {
00201         throw PGSTD::runtime_error("Error reading field " + 
00202                                    PGSTD::string(name()) +
00203                                    ": " +
00204                                    e.what());
00205       }
00206       return true;
00207     }
00208 
00209 
00210 #ifdef PQXX_NO_PARTIAL_CLASS_TEMPLATE_SPECIALISATION
00211 
00212     template<> bool to<PGSTD::string>(PGSTD::string &Obj) const;
00213 
00215 
00218     template<> bool to<const char *>(const char *&Obj) const;
00219 #endif
00220 
00221 
00223     template<typename T> bool to(T &Obj, const T &Default) const        //[t12]
00224     {
00225       const bool NotNull = to(Obj);
00226       if (!NotNull)
00227         Obj = Default;
00228       return NotNull;
00229     }
00230 
00232 
00235     template<typename T> T as(const T &Default) const                   //[t1]
00236     {
00237       T Obj;
00238       to(Obj, Default);
00239       return Obj;
00240     }
00241 
00242     bool is_null() const { return m_Home->GetIsNull(m_Index,m_Col); }   //[t12]
00243 
00244     size_type size() const { return m_Home->GetLength(m_Index,m_Col); } //[t11]
00245 
00246   private:
00247 
00248     tuple::size_type m_Col;
00249   };
00250 
00251 #ifdef PQXX_DEPRECATED_HEADERS
00252 
00253   typedef field Field;
00254 #endif
00255 
00257 
00261   class PQXX_LIBEXPORT const_iterator : 
00262     public PGSTD::iterator<PGSTD::random_access_iterator_tag, 
00263                          const tuple,
00264                          result::size_type>, 
00265     public tuple
00266   {
00267   public:
00268     const_iterator() : tuple(0,0) {}
00269 
00276     pointer operator->()  const { return this; }                        //[t12]
00277     reference operator*() const { return *operator->(); }               //[t12]
00278 
00279     const_iterator operator++(int);                                     //[t12]
00280     const_iterator &operator++() { ++m_Index; return *this; }           //[t1]
00281     const_iterator operator--(int);                                     //[t12]
00282     const_iterator &operator--() { --m_Index; return *this; }           //[t12]
00283 
00284     const_iterator &operator+=(difference_type i)                       //[t12]
00285         { m_Index+=i; return *this; }
00286     const_iterator &operator-=(difference_type i)                       //[t12]
00287         { m_Index-=i; return *this; }
00288 
00289     bool operator==(const const_iterator &i) const                      //[t12]
00290         {return m_Index==i.m_Index;}
00291     bool operator!=(const const_iterator &i) const                      //[t12]
00292         {return m_Index!=i.m_Index;}
00293     bool operator<(const const_iterator &i) const                       //[t12]
00294          {return m_Index<i.m_Index;}
00295     bool operator<=(const const_iterator &i) const                      //[t12]
00296         {return m_Index<=i.m_Index;}
00297     bool operator>(const const_iterator &i) const                       //[t12]
00298         {return m_Index>i.m_Index;}
00299     bool operator>=(const const_iterator &i) const                      //[t12]
00300         {return m_Index>=i.m_Index;}
00301 
00302     inline const_iterator operator+(difference_type o) const;           //[t12]
00303 
00304     friend const_iterator operator+(difference_type o, 
00305                                     const_iterator i);                  //[t12]
00306 
00307     inline const_iterator operator-(difference_type o) const;           //[t12]
00308 
00309     inline difference_type operator-(const_iterator i) const;           //[t12]
00310 
00311     result::size_type num() const { return rownumber(); }               //[t1]
00312 
00313   private:
00314     friend class result;
00315     const_iterator(const result *r, result::size_type i) : tuple(r, i) {}
00316   };
00317 
00318   const_iterator begin() const { return const_iterator(this, 0); }      //[t1]
00319   inline const_iterator end() const;                                    //[t1]
00320   // TODO: Reverse iterators
00321 
00322   size_type size() const { return m_Result ? PQntuples(m_Result) : 0; } //[t2]
00323   bool empty() const { return !m_Result || !PQntuples(m_Result); }      //[t11]
00324   size_type capacity() const { return size(); }                         //[t20]
00325 
00326   const tuple operator[](size_type i) const { return tuple(this, i); }  //[t2]
00327   const tuple at(size_type) const;                                      //[t10]
00328 
00329   void clear() { LoseRef(); }                                           //[t20]
00330 
00331 #ifdef PQXX_DEPRECATED_HEADERS
00332 
00333   tuple::size_type Columns() const { return columns(); }
00334 
00336   tuple::size_type ColumnNumber(const char Name[]) const
00337         {return PQfnumber(m_Result,Name);}
00339   tuple::size_type ColumnNumber(const PGSTD::string &Name) const
00340         {return ColumnNumber(Name.c_str());}
00342   const char *ColumnName(tuple::size_type Number) const
00343         {return PQfname(m_Result,Number);}
00344 #endif
00345 
00347   tuple::size_type columns() const { return PQnfields(m_Result); }      //[t11]
00348 
00350   tuple::size_type column_number(const char ColName[]) const;           //[t11]
00351 
00353   tuple::size_type column_number(const PGSTD::string &Name) const       //[t11]
00354         {return column_number(Name.c_str());}
00355 
00357   const char *column_name(tuple::size_type Number) const;               //[t11]
00358 
00360   inline oid column_type(tuple::size_type ColNum) const;                //[t7]
00361 
00363   oid column_type(const PGSTD::string &ColName) const                   //[t7]
00364         { return column_type(column_number(ColName)); }
00365 
00367   oid column_type(const char ColName[]) const                           //[t7]
00368         { return column_type(column_number(ColName)); }
00369 
00370 #ifdef PQXX_HAVE_PQFTABLE
00371 
00372   oid column_table(tuple::size_type ColNum) const;                      //[t2]
00373 
00375   oid column_table(const PGSTD::string &ColName) const                  //[t2]
00376         { return column_table(column_number(ColName)); }
00377 #endif
00378 
00379 #ifdef PQXX_DEPRECATED_HEADERS
00380 
00381   oid InsertedOid() const { return inserted_oid(); }
00383   size_type AffectedRows() const { return affected_rows(); }
00384 #endif
00385 
00387 
00389   oid inserted_oid() const { return PQoidValue(m_Result); }             //[t13]
00390 
00391 
00393   /*** Returns zero for all other commands. */
00394   size_type affected_rows() const;                                      //[t7]
00395 
00396 private:
00397   PGresult *m_Result;
00398   mutable int *m_Refcount;
00399 
00400   friend class result::field;
00401   const char *GetValue(size_type Row, tuple::size_type Col) const;
00402   bool GetIsNull(size_type Row, tuple::size_type Col) const;
00403   field::size_type GetLength(size_type Row, tuple::size_type Col) const;
00404 
00405   friend class connection_base;
00406   explicit result(PGresult *rhs) : m_Result(rhs), m_Refcount(0) {MakeRef(rhs);}
00407   result &operator=(PGresult *);
00408   bool operator!() const throw () { return !m_Result; }
00409   operator bool() const throw () { return m_Result != 0; }
00410   void CheckStatus(const PGSTD::string &Query) const;
00411 
00412   friend class Cursor;
00413   const char *CmdStatus() const throw () { return PQcmdStatus(m_Result); }
00414 
00415 
00416   void MakeRef(PGresult *);
00417   void MakeRef(const result &);
00418   void LoseRef() throw ();
00419 };
00420 
00421 
00423 
00440 template<typename STREAM>
00441 inline STREAM &operator<<(STREAM &S, const pqxx::result::field &F)      //[t46]
00442 {
00443   S << F.c_str();
00444   return S;
00445 }
00446 
00447 
00448 
00449 inline result::field 
00450 result::tuple::operator[](result::tuple::size_type i) const 
00451 { 
00452   return field(*this, i); 
00453 }
00454 
00455 inline result::tuple::size_type result::tuple::size() const 
00456 { 
00457   return m_Home->columns(); 
00458 }
00459 
00460 inline const char *result::field::name() const 
00461 { 
00462   return m_Home->column_name(m_Col); 
00463 }
00464 
00466 template<> 
00467 inline bool result::field::to<PGSTD::string>(PGSTD::string &Obj) const
00468 {
00469   if (is_null()) return false;
00470   Obj = c_str();
00471   return true;
00472 }
00473 
00475 
00478 template<> 
00479 inline bool result::field::to<const char *>(const char *&Obj) const
00480 {
00481   if (is_null()) return false;
00482   Obj = c_str();
00483   return true;
00484 }
00485 
00486 
00487 inline result::const_iterator 
00488 result::const_iterator::operator+(difference_type o) const
00489 {
00490   return const_iterator(m_Home, m_Index + o);
00491 }
00492 
00493 inline result::const_iterator 
00494 operator+(result::const_iterator::difference_type o, 
00495           result::const_iterator i)
00496 {
00497   return i + o;
00498 }
00499 
00500 inline result::const_iterator 
00501 result::const_iterator::operator-(difference_type o) const
00502 {
00503   return const_iterator(m_Home, m_Index - o);
00504 }
00505 
00506 inline result::const_iterator::difference_type 
00507 result::const_iterator::operator-(const_iterator i) const
00508 { 
00509   return num()-i.num(); 
00510 }
00511 
00512 inline result::const_iterator result::end() const 
00513 { 
00514   return const_iterator(this, size()); 
00515 }
00516 
00517 inline oid result::column_type(tuple::size_type ColNum) const
00518 {
00519   const oid T = PQftype(m_Result, ColNum);
00520   if (T == oid_none)
00521     throw PGSTD::invalid_argument(
00522                 "Attempt to retrieve type of nonexistant column " +
00523                 ToString(ColNum) + " "
00524                 "of query result");
00525   return T;
00526 }
00527 
00528 
00529 #ifdef PQXX_HAVE_PQFTABLE
00530 inline oid result::column_table(tuple::size_type ColNum) const
00531 {
00532   const oid T = PQftable(m_Result, ColNum);
00533 
00534   /* If we get InvalidOid, it may be because the column is computed, or because
00535    * we got an invalid row number.
00536    */
00537   // TODO: Skip this if we first computed the column name ourselves
00538   if ((T == InvalidOid) &&
00539       ((ColNum < 0) || (ColNum >= columns())))
00540     throw PGSTD::invalid_argument("Attempt to retrieve table ID for column " +
00541                                   ToString(ColNum) + " "
00542                                   "out of " + ToString(columns()));
00543   return T;
00544 }
00545 #endif
00546 
00547 } // namespace pqxx
00548 
00549 
00550 
00551 /* 
00552 [1] Scott Meyers, in one of his essential books, "Effective C++" and "More 
00553 Effective C++", points out that it is good style to have any class containing 
00554 a member of pointer type define its own destructor--just to show that it knows
00555 what it is doing.  This helps prevent nasty memory leak / double deletion bugs
00556 typically resulting from programmers' omission to deal with such issues in
00557 their destructors.
00558 
00559 The -Weffc++ option in gcc generates warnings for noncompliance with Scott's
00560 style guidelines, and hence necessitates the definition of this destructor,\
00561 trivial as it may be.
00562 
00563 [2] IIRC Alex Stepanov, the inventor of the STL, once remarked that having
00564 this as standard behaviour for pointers would be useful in some algorithms.
00565 So even if this makes me look foolish, I would seem to be in distinguished 
00566 company.
00567 */
00568 
00569 

Generated on Mon Oct 13 13:20:13 2003 for libpqxx by doxygen 1.3.4