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 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) throw() : 
00069       m_Home(r), m_Index(i) {}
00070     ~tuple() {} // Yes Scott Meyers, you're absolutely right[1]
00071 
00072     inline field operator[](size_type) const throw ();                  //[t1]
00073     field operator[](const char[]) const;                               //[t11]
00074     field operator[](const PGSTD::string &s) const                      //[t11]
00075         { return operator[](s.c_str()); }
00076     field at(size_type) const throw (PGSTD::out_of_range);              //[t10]
00077     field at(const char[]) const;                                       //[t11]
00078     field at(const PGSTD::string &s) const { return at(s.c_str()); }    //[t11]
00079 
00080     inline size_type size() const;                                      //[t11]
00081 
00082 #ifdef PQXX_DEPRECATED_HEADERS
00083 
00084     result::size_type Row() const { return rownumber(); }
00085 
00087     size_type ColumnNumber(const PGSTD::string &ColName) const 
00088         { return m_Home->ColumnNumber(ColName); }
00089 
00091     size_type ColumnNumber(const char ColName[]) const 
00092         { return m_Home->ColumnNumber(ColName); }
00093 #endif
00094 
00095     result::size_type rownumber() const { return m_Index; }             //[t11]
00096 
00098     size_type column_number(const PGSTD::string &ColName) const         //[t30]
00099         { return m_Home->column_number(ColName); }
00100 
00102     size_type column_number(const char ColName[]) const                 //[t30]
00103         { return m_Home->column_number(ColName); }
00104 
00106     oid column_type(size_type ColNum) const                             //[t7]
00107         { return m_Home->column_type(ColNum); }
00108 
00110     oid column_type(const PGSTD::string &ColName) const                 //[t7]
00111         { return column_type(column_number(ColName)); }
00112 
00114     oid column_type(const char ColName[]) const                         //[t7]
00115         { return column_type(column_number(ColName)); }
00116 
00117 #ifdef PQXX_HAVE_PQFTABLE
00118     oid column_table(size_type ColNum) const                            //[t2]
00119         { return m_Home->column_table(ColNum); }
00120     oid column_table(const PGSTD::string &ColName) const                //[t2]
00121         { return column_table(column_number(ColName)); }
00122 #endif
00123 
00124   protected:
00125     const result *m_Home;
00126     result::size_type m_Index;
00127 
00128     // Not allowed:
00129     tuple();
00130   };
00131 
00132 #ifdef PQXX_DEPRECATED_HEADERS
00133 
00134   typedef tuple Tuple;
00135 #endif
00136 
00137 
00139 
00142   class PQXX_LIBEXPORT field : private tuple
00143   {
00144   public:
00145     typedef size_t size_type;
00146 
00148 
00152     field(const tuple &R, tuple::size_type C) throw () :                //[t1]
00153         tuple(R), m_Col(C) {}
00154 
00156 
00161     const char *c_str() const {return m_Home->GetValue(m_Index,m_Col);} //[t2]
00162 
00163 #ifdef PQXX_DEPRECATED_HEADERS
00164 
00165     const char *Name() const {return name();}
00166 #endif
00167 
00169     inline const char *name() const;                                    //[t11]
00170 
00172     oid type() const                                                    //[t7]
00173         { return m_Home->column_type(m_Col); }
00174 
00175 #ifdef PQXX_HAVE_PQFTABLE
00176 
00177 
00179     oid table() const { return m_Home->column_table(m_Col); }           //[t2]
00180 #endif
00181 
00183 
00192     template<typename T> bool to(T &Obj) const                          //[t3]
00193     {
00194       if (is_null())
00195         return false;
00196 
00197       try
00198       {
00199         FromString(c_str(), Obj);
00200       }
00201       catch (const PGSTD::exception &e)
00202       {
00203         throw PGSTD::domain_error("Error reading field " + 
00204                                   PGSTD::string(name()) +
00205                                   ": " +
00206                                   e.what());
00207       }
00208       return true;
00209     }
00210 
00211 
00212 #ifdef PQXX_NO_PARTIAL_CLASS_TEMPLATE_SPECIALISATION
00213 
00214     template<> bool to<PGSTD::string>(PGSTD::string &Obj) const;
00215 
00217 
00220     template<> bool to<const char *>(const char *&Obj) const;
00221 #endif
00222 
00223 
00225     template<typename T> bool to(T &Obj, const T &Default) const        //[t12]
00226     {
00227       const bool NotNull = to(Obj);
00228       if (!NotNull)
00229         Obj = Default;
00230       return NotNull;
00231     }
00232 
00234 
00237     template<typename T> T as(const T &Default) const                   //[t1]
00238     {
00239       T Obj;
00240       to(Obj, Default);
00241       return Obj;
00242     }
00243 
00245     template<typename T> T as() const                                   //[t45]
00246     {
00247       T Obj;
00248       const bool NotNull = to(Obj);
00249       if (!NotNull) throw PGSTD::domain_error("Attempt to read null field");
00250       return Obj;
00251     }
00252 
00253     bool is_null() const { return m_Home->GetIsNull(m_Index,m_Col); }   //[t12]
00254 
00255     size_type size() const { return m_Home->GetLength(m_Index,m_Col); } //[t11]
00256 
00257   private:
00258 
00259     tuple::size_type m_Col;
00260   };
00261 
00262 #ifdef PQXX_DEPRECATED_HEADERS
00263 
00264   typedef field Field;
00265 #endif
00266 
00268 
00272   class PQXX_LIBEXPORT const_iterator : 
00273     public PGSTD::iterator<PGSTD::random_access_iterator_tag, 
00274                          const tuple,
00275                          result::size_type>, 
00276     public tuple
00277   {
00278   public:
00279     const_iterator() : tuple(0,0) {}
00280 
00287     pointer operator->()  const { return this; }                        //[t12]
00288     reference operator*() const { return *operator->(); }               //[t12]
00289 
00290     const_iterator operator++(int);                                     //[t12]
00291     const_iterator &operator++() { ++m_Index; return *this; }           //[t1]
00292     const_iterator operator--(int);                                     //[t12]
00293     const_iterator &operator--() { --m_Index; return *this; }           //[t12]
00294 
00295     const_iterator &operator+=(difference_type i)                       //[t12]
00296         { m_Index+=i; return *this; }
00297     const_iterator &operator-=(difference_type i)                       //[t12]
00298         { m_Index-=i; return *this; }
00299 
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     bool operator<(const const_iterator &i) const                       //[t12]
00305          {return m_Index<i.m_Index;}
00306     bool operator<=(const const_iterator &i) const                      //[t12]
00307         {return m_Index<=i.m_Index;}
00308     bool operator>(const const_iterator &i) const                       //[t12]
00309         {return m_Index>i.m_Index;}
00310     bool operator>=(const const_iterator &i) const                      //[t12]
00311         {return m_Index>=i.m_Index;}
00312 
00313     inline const_iterator operator+(difference_type o) const;           //[t12]
00314 
00315     friend const_iterator operator+(difference_type o, 
00316                                     const_iterator i);                  //[t12]
00317 
00318     inline const_iterator operator-(difference_type o) const;           //[t12]
00319 
00320     inline difference_type operator-(const_iterator i) const;           //[t12]
00321 
00322     result::size_type num() const { return rownumber(); }               //[t1]
00323 
00324   private:
00325     friend class result;
00326     const_iterator(const result *r, result::size_type i) : tuple(r, i) {}
00327   };
00328 
00329   const_iterator begin() const { return const_iterator(this, 0); }      //[t1]
00330   inline const_iterator end() const;                                    //[t1]
00331   // TODO: Reverse iterators
00332 
00333   size_type size() const { return m_Result ? PQntuples(m_Result) : 0; } //[t2]
00334   bool empty() const { return !m_Result || !PQntuples(m_Result); }      //[t11]
00335   size_type capacity() const { return size(); }                         //[t20]
00336 
00337   const tuple operator[](size_type i) const throw ()                    //[t2]
00338         { return tuple(this, i); }
00339   const tuple at(size_type) const throw (PGSTD::out_of_range);          //[t10]
00340 
00341   void clear() { LoseRef(); }                                           //[t20]
00342 
00343 #ifdef PQXX_DEPRECATED_HEADERS
00344 
00345   tuple::size_type Columns() const { return columns(); }
00346 
00348   tuple::size_type ColumnNumber(const char Name[]) const
00349         {return PQfnumber(m_Result,Name);}
00351   tuple::size_type ColumnNumber(const PGSTD::string &Name) const
00352         {return ColumnNumber(Name.c_str());}
00354   const char *ColumnName(tuple::size_type Number) const
00355         {return PQfname(m_Result,Number);}
00356 #endif
00357 
00359   tuple::size_type columns() const { return PQnfields(m_Result); }      //[t11]
00360 
00362   tuple::size_type column_number(const char ColName[]) const;           //[t11]
00363 
00365   tuple::size_type column_number(const PGSTD::string &Name) const       //[t11]
00366         {return column_number(Name.c_str());}
00367 
00369   const char *column_name(tuple::size_type Number) const;               //[t11]
00370 
00372   inline oid column_type(tuple::size_type ColNum) const;                //[t7]
00373 
00375   oid column_type(const PGSTD::string &ColName) const                   //[t7]
00376         { return column_type(column_number(ColName)); }
00377 
00379   oid column_type(const char ColName[]) const                           //[t7]
00380         { return column_type(column_number(ColName)); }
00381 
00382 #ifdef PQXX_HAVE_PQFTABLE
00383 
00384   oid column_table(tuple::size_type ColNum) const;                      //[t2]
00385 
00387   oid column_table(const PGSTD::string &ColName) const                  //[t2]
00388         { return column_table(column_number(ColName)); }
00389 #endif
00390 
00391 #ifdef PQXX_DEPRECATED_HEADERS
00392 
00393   oid InsertedOid() const { return inserted_oid(); }
00395   size_type AffectedRows() const { return affected_rows(); }
00396 #endif
00397 
00399 
00401   oid inserted_oid() const { return PQoidValue(m_Result); }             //[t13]
00402 
00403 
00405   /*** Returns zero for all other commands. */
00406   size_type affected_rows() const;                                      //[t7]
00407 
00408 private:
00409   PGresult *m_Result;
00410   mutable int *m_Refcount;
00411 
00412   friend class result::field;
00413   const char *GetValue(size_type Row, tuple::size_type Col) const;
00414   bool GetIsNull(size_type Row, tuple::size_type Col) const;
00415   field::size_type GetLength(size_type Row, tuple::size_type Col) const;
00416 
00417   friend class connection_base;
00418   explicit result(PGresult *rhs) : m_Result(rhs), m_Refcount(0) {MakeRef(rhs);}
00419   result &operator=(PGresult *);
00420   bool operator!() const throw () { return !m_Result; }
00421   operator bool() const throw () { return m_Result != 0; }
00422   void CheckStatus(const PGSTD::string &Query) const;
00423 
00424   friend class Cursor;
00425   const char *CmdStatus() const throw () { return PQcmdStatus(m_Result); }
00426 
00427 
00428   void MakeRef(PGresult *);
00429   void MakeRef(const result &);
00430   void LoseRef() throw ();
00431 };
00432 
00433 
00435 
00452 template<typename STREAM>
00453 inline STREAM &operator<<(STREAM &S, const pqxx::result::field &F)      //[t46]
00454 {
00455   S << F.c_str();
00456   return S;
00457 }
00458 
00459 
00460 
00461 inline result::field 
00462 result::tuple::operator[](result::tuple::size_type i) const  throw ()
00463 { 
00464   return field(*this, i); 
00465 }
00466 
00467 inline result::tuple::size_type result::tuple::size() const 
00468 { 
00469   return m_Home->columns(); 
00470 }
00471 
00472 inline const char *result::field::name() const 
00473 { 
00474   return m_Home->column_name(m_Col); 
00475 }
00476 
00478 template<> 
00479 inline bool result::field::to<PGSTD::string>(PGSTD::string &Obj) const
00480 {
00481   if (is_null()) return false;
00482   Obj = c_str();
00483   return true;
00484 }
00485 
00487 
00490 template<> 
00491 inline bool result::field::to<const char *>(const char *&Obj) const
00492 {
00493   if (is_null()) return false;
00494   Obj = c_str();
00495   return true;
00496 }
00497 
00498 
00499 inline result::const_iterator 
00500 result::const_iterator::operator+(difference_type o) const
00501 {
00502   return const_iterator(m_Home, m_Index + o);
00503 }
00504 
00505 inline result::const_iterator 
00506 operator+(result::const_iterator::difference_type o, 
00507           result::const_iterator i)
00508 {
00509   return i + o;
00510 }
00511 
00512 inline result::const_iterator 
00513 result::const_iterator::operator-(difference_type o) const
00514 {
00515   return const_iterator(m_Home, m_Index - o);
00516 }
00517 
00518 inline result::const_iterator::difference_type 
00519 result::const_iterator::operator-(const_iterator i) const
00520 { 
00521   return num()-i.num(); 
00522 }
00523 
00524 inline result::const_iterator result::end() const 
00525 { 
00526   return const_iterator(this, size()); 
00527 }
00528 
00529 inline oid result::column_type(tuple::size_type ColNum) const
00530 {
00531   const oid T = PQftype(m_Result, ColNum);
00532   if (T == oid_none)
00533     throw PGSTD::invalid_argument(
00534                 "Attempt to retrieve type of nonexistant column " +
00535                 ToString(ColNum) + " "
00536                 "of query result");
00537   return T;
00538 }
00539 
00540 
00541 #ifdef PQXX_HAVE_PQFTABLE
00542 inline oid result::column_table(tuple::size_type ColNum) const
00543 {
00544   const oid T = PQftable(m_Result, ColNum);
00545 
00546   /* If we get InvalidOid, it may be because the column is computed, or because
00547    * we got an invalid row number.
00548    */
00549   // TODO: Skip this if we first computed the column name ourselves
00550   if ((T == InvalidOid) &&
00551       ((ColNum < 0) || (ColNum >= columns())))
00552     throw PGSTD::invalid_argument("Attempt to retrieve table ID for column " +
00553                                   ToString(ColNum) + " "
00554                                   "out of " + ToString(columns()));
00555   return T;
00556 }
00557 #endif
00558 
00559 } // namespace pqxx
00560 
00561 
00562 
00563 /* 
00564 [1] Scott Meyers, in one of his essential books, "Effective C++" and "More 
00565 Effective C++", points out that it is good style to have any class containing 
00566 a member of pointer type define its own destructor--just to show that it knows
00567 what it is doing.  This helps prevent nasty memory leak / double deletion bugs
00568 typically resulting from programmers' omission to deal with such issues in
00569 their destructors.
00570 
00571 The -Weffc++ option in gcc generates warnings for noncompliance with Scott's
00572 style guidelines, and hence necessitates the definition of this destructor,\
00573 trivial as it may be.
00574 
00575 [2] IIRC Alex Stepanov, the inventor of the STL, once remarked that having
00576 this as standard behaviour for pointers would be useful in some algorithms.
00577 So even if this makes me look foolish, I would seem to be in distinguished 
00578 company.
00579 */
00580 
00581 

Generated on Fri Oct 24 20:21:37 2003 for libpqxx by doxygen 1.3.4