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-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 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() : 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) throw() : 
00071       m_Home(r), m_Index(i) {}
00072     ~tuple() {} // 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;                                      //[t11]
00083 
00084     result::size_type rownumber() const { 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         FromString(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   const_iterator begin() const { return const_iterator(this, 0); }      //[t1]
00322   inline const_iterator end() const;                                    //[t1]
00323   // TODO: Reverse iterators
00324 
00325   size_type size() const { return m_Result ? PQntuples(m_Result) : 0; } //[t2]
00326   bool empty() const { return !m_Result || !PQntuples(m_Result); }      //[t11]
00327   size_type capacity() const { return size(); }                         //[t20]
00328 
00329   const tuple operator[](size_type i) const throw ()                    //[t2]
00330         { return tuple(this, i); }
00331   const tuple at(size_type) const throw (PGSTD::out_of_range);          //[t10]
00332 
00333   void clear() { LoseRef(); }                                           //[t20]
00334 
00336   tuple::size_type columns() const { return PQnfields(m_Result); }      //[t11]
00337 
00339   tuple::size_type column_number(const char ColName[]) const;           //[t11]
00340 
00342   tuple::size_type column_number(const PGSTD::string &Name) const       //[t11]
00343         {return column_number(Name.c_str());}
00344 
00346   const char *column_name(tuple::size_type Number) const;               //[t11]
00347 
00349   inline oid column_type(tuple::size_type ColNum) const;                //[t7]
00350 
00352   oid column_type(const PGSTD::string &ColName) const                   //[t7]
00353         { return column_type(column_number(ColName)); }
00354 
00356   oid column_type(const char ColName[]) const                           //[t7]
00357         { return column_type(column_number(ColName)); }
00358 
00359 #ifdef PQXX_HAVE_PQFTABLE
00360 
00361   oid column_table(tuple::size_type ColNum) const;                      //[t2]
00362 
00364   oid column_table(const PGSTD::string &ColName) const                  //[t2]
00365         { return column_table(column_number(ColName)); }
00366 #endif
00367 
00368 
00370 
00372   oid inserted_oid() const { return PQoidValue(m_Result); }             //[t13]
00373 
00374 
00376   /*** Returns zero for all other commands. */
00377   size_type affected_rows() const;                                      //[t7]
00378 
00379 
00380 #ifdef PQXX_DEPRECATED_HEADERS
00381 
00382   typedef tuple Tuple;
00384   typedef field Field;
00386   oid InsertedOid() const { return inserted_oid(); }
00388   size_type AffectedRows() const { return affected_rows(); }
00390   tuple::size_type Columns() const { return columns(); }
00392   tuple::size_type ColumnNumber(const char Name[]) const
00393         {return PQfnumber(m_Result,Name);}
00395   tuple::size_type ColumnNumber(const PGSTD::string &Name) const
00396         {return ColumnNumber(Name.c_str());}
00398   const char *ColumnName(tuple::size_type Number) const
00399         {return PQfname(m_Result,Number);}
00400 #endif
00401 
00402 
00403 private:
00404   PGresult *m_Result;
00405   mutable int *m_Refcount;
00406 
00407   friend class result::field;
00408   const char *GetValue(size_type Row, tuple::size_type Col) const;
00409   bool GetIsNull(size_type Row, tuple::size_type Col) const;
00410   field::size_type GetLength(size_type Row, tuple::size_type Col) const;
00411 
00412   friend class connection_base;
00413   explicit result(PGresult *rhs) : m_Result(rhs), m_Refcount(0) {MakeRef(rhs);}
00414   result &operator=(PGresult *);
00415   bool operator!() const throw () { return !m_Result; }
00416   operator bool() const throw () { return m_Result != 0; }
00417   void CheckStatus(const PGSTD::string &Query) const;
00418   void CheckStatus(const char Query[]) const;
00419   PGSTD::string StatusError() const;
00420 
00421   friend class Cursor;
00422   const char *CmdStatus() const throw () { return PQcmdStatus(m_Result); }
00423 
00424 
00425   void MakeRef(PGresult *);
00426   void MakeRef(const result &);
00427   void LoseRef() throw ();
00428 };
00429 
00430 
00432 
00449 template<typename STREAM>
00450 inline STREAM &operator<<(STREAM &S, const pqxx::result::field &F)      //[t46]
00451 {
00452   S.write(F.c_str(), F.size());
00453   return S;
00454 }
00455 
00456 
00457 
00458 inline result::field 
00459 result::tuple::operator[](result::tuple::size_type i) const  throw ()
00460 { 
00461   return field(*this, i); 
00462 }
00463 
00464 inline result::tuple::size_type result::tuple::size() const 
00465 { 
00466   return m_Home->columns(); 
00467 }
00468 
00469 inline const char *result::field::name() const 
00470 { 
00471   return m_Home->column_name(m_Col); 
00472 }
00473 
00475 template<> 
00476 inline bool result::field::to<PGSTD::string>(PGSTD::string &Obj) const
00477 {
00478   if (is_null()) return false;
00479   Obj = c_str();
00480   return true;
00481 }
00482 
00484 
00487 template<> 
00488 inline bool result::field::to<const char *>(const char *&Obj) const
00489 {
00490   if (is_null()) return false;
00491   Obj = c_str();
00492   return true;
00493 }
00494 
00495 
00496 inline result::const_iterator 
00497 result::const_iterator::operator+(difference_type o) const
00498 {
00499   return const_iterator(m_Home, m_Index + o);
00500 }
00501 
00502 inline result::const_iterator 
00503 operator+(result::const_iterator::difference_type o, 
00504           result::const_iterator i)
00505 {
00506   return i + o;
00507 }
00508 
00509 inline result::const_iterator 
00510 result::const_iterator::operator-(difference_type o) const
00511 {
00512   return const_iterator(m_Home, m_Index - o);
00513 }
00514 
00515 inline result::const_iterator::difference_type 
00516 result::const_iterator::operator-(const_iterator i) const
00517 { 
00518   return num()-i.num(); 
00519 }
00520 
00521 inline result::const_iterator result::end() const 
00522 { 
00523   return const_iterator(this, size()); 
00524 }
00525 
00526 inline oid result::column_type(tuple::size_type ColNum) const
00527 {
00528   const oid T = PQftype(m_Result, ColNum);
00529   if (T == oid_none)
00530     throw PGSTD::invalid_argument(
00531                 "Attempt to retrieve type of nonexistant column " +
00532                 ToString(ColNum) + " "
00533                 "of query result");
00534   return T;
00535 }
00536 
00537 
00538 #ifdef PQXX_HAVE_PQFTABLE
00539 inline oid result::column_table(tuple::size_type ColNum) const
00540 {
00541   const oid T = PQftable(m_Result, ColNum);
00542 
00543   /* If we get InvalidOid, it may be because the column is computed, or because
00544    * we got an invalid row number.
00545    */
00546   // TODO: Skip this if we first computed the column name ourselves
00547   if ((T == InvalidOid) &&
00548       ((ColNum < 0) || (ColNum >= columns())))
00549     throw PGSTD::invalid_argument("Attempt to retrieve table ID for column " +
00550                                   ToString(ColNum) + " "
00551                                   "out of " + ToString(columns()));
00552   return T;
00553 }
00554 #endif
00555 
00556 } // namespace pqxx
00557 
00558 
00559 
00560 /* 
00561 [1] Scott Meyers, in one of his essential books, "Effective C++" and "More 
00562 Effective C++", points out that it is good style to have any class containing 
00563 a member of pointer type define its own destructor--just to show that it knows
00564 what it is doing.  This helps prevent nasty memory leak / double deletion bugs
00565 typically resulting from programmers' omission to deal with such issues in
00566 their destructors.
00567 
00568 The -Weffc++ option in gcc generates warnings for noncompliance with Scott's
00569 style guidelines, and hence necessitates the definition of this destructor,\
00570 trivial as it may be.
00571 
00572 [2] IIRC Alex Stepanov, the inventor of the STL, once remarked that having
00573 this as standard behaviour for pointers would be useful in some algorithms.
00574 So even if this makes me look foolish, I would seem to be in distinguished 
00575 company.
00576 */
00577 
00578 

Generated on Thu Dec 25 07:22:37 2003 for libpqxx by doxygen 1.3.4