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-2004, 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 #ifdef PQXX_HAVE_IOS 00020 #include <ios> 00021 #endif 00022 00023 #include <stdexcept> 00024 00025 #include "pqxx/util" 00026 00027 /* Methods tested in eg. self-test program test001 are marked with "//[t1]" 00028 */ 00029 00030 00031 // TODO: Support SQL arrays 00032 // TODO: value_type, reference, const_reference, difference_type 00033 // TODO: container comparisons 00034 00035 namespace pqxx 00036 { 00037 00039 00046 class PQXX_LIBEXPORT result 00047 { 00048 public: 00049 result() throw () : m_Result(0), m_Refcount(0) {} //[t3] 00050 result(const result &rhs) throw () : //[t1] 00051 m_Result(0), m_Refcount(0) { MakeRef(rhs); } 00052 ~result() { LoseRef(); } //[t1] 00053 00054 result &operator=(const result &) throw (); //[t10] 00055 00056 typedef result_size_type size_type; 00057 class field; 00058 00059 // TODO: Field iterators 00060 00062 00070 class PQXX_LIBEXPORT tuple 00071 { 00072 public: 00073 typedef tuple_size_type size_type; 00074 tuple(const result *r, result::size_type i) throw () : 00075 m_Home(r), m_Index(i) {} 00076 ~tuple() throw () {} // Yes Scott Meyers, you're absolutely right[1] 00077 00078 inline field operator[](size_type) const throw (); //[t1] 00079 field operator[](const char[]) const; //[t11] 00080 field operator[](const PGSTD::string &s) const //[t11] 00081 { return operator[](s.c_str()); } 00082 field at(size_type) const throw (PGSTD::out_of_range); //[t10] 00083 field at(const char[]) const; //[t11] 00084 field at(const PGSTD::string &s) const { return at(s.c_str()); } //[t11] 00085 00086 inline size_type size() const throw (); //[t11] 00087 00088 result::size_type rownumber() const throw () { return m_Index; } //[t11] 00089 00091 size_type column_number(const PGSTD::string &ColName) const //[t30] 00092 { return m_Home->column_number(ColName); } 00093 00095 size_type column_number(const char ColName[]) const //[t30] 00096 { return m_Home->column_number(ColName); } 00097 00099 oid column_type(size_type ColNum) const //[t7] 00100 { return m_Home->column_type(ColNum); } 00101 00103 oid column_type(const PGSTD::string &ColName) const //[t7] 00104 { return column_type(column_number(ColName)); } 00105 00107 oid column_type(const char ColName[]) const //[t7] 00108 { return column_type(column_number(ColName)); } 00109 00110 #ifdef PQXX_HAVE_PQFTABLE 00111 oid column_table(size_type ColNum) const //[t2] 00112 { return m_Home->column_table(ColNum); } 00113 oid column_table(const PGSTD::string &ColName) const //[t2] 00114 { return column_table(column_number(ColName)); } 00115 #endif 00116 00117 00118 #ifdef PQXX_DEPRECATED_HEADERS 00119 00120 result::size_type Row() const { return rownumber(); } 00121 00123 size_type ColumnNumber(const PGSTD::string &ColName) const 00124 { return m_Home->ColumnNumber(ColName); } 00125 00127 size_type ColumnNumber(const char ColName[]) const 00128 { return m_Home->ColumnNumber(ColName); } 00129 #endif 00130 00131 00132 protected: 00133 const result *m_Home; 00134 result::size_type m_Index; 00135 00136 // Not allowed: 00137 tuple(); 00138 }; 00139 00141 00144 class PQXX_LIBEXPORT field : private tuple 00145 { 00146 public: 00147 typedef size_t size_type; 00148 00150 00154 field(const tuple &R, tuple::size_type C) throw () : //[t1] 00155 tuple(R), m_Col(C) {} 00156 00158 00163 const char *c_str() const {return m_Home->GetValue(m_Index,m_Col);} //[t2] 00164 00166 inline const char *name() const; //[t11] 00167 00169 oid type() const //[t7] 00170 { return m_Home->column_type(m_Col); } 00171 00172 #ifdef PQXX_HAVE_PQFTABLE 00173 00174 00176 oid table() const { return m_Home->column_table(m_Col); } //[t2] 00177 #endif 00178 00180 00189 template<typename T> bool to(T &Obj) const //[t3] 00190 { 00191 if (is_null()) 00192 return false; 00193 00194 try 00195 { 00196 from_string(c_str(), Obj); 00197 } 00198 catch (const PGSTD::exception &e) 00199 { 00200 throw PGSTD::domain_error("Error reading field " + 00201 PGSTD::string(name()) + 00202 ": " + 00203 e.what()); 00204 } 00205 return true; 00206 } 00207 00208 00209 #ifdef PQXX_NO_PARTIAL_CLASS_TEMPLATE_SPECIALISATION 00210 00211 template<> bool to<PGSTD::string>(PGSTD::string &Obj) const; 00212 00214 00217 template<> bool to<const char *>(const char *&Obj) const; 00218 #endif 00219 00220 00222 template<typename T> bool to(T &Obj, const T &Default) const //[t12] 00223 { 00224 const bool NotNull = to(Obj); 00225 if (!NotNull) 00226 Obj = Default; 00227 return NotNull; 00228 } 00229 00231 00234 template<typename T> T as(const T &Default) const //[t1] 00235 { 00236 T Obj; 00237 to(Obj, Default); 00238 return Obj; 00239 } 00240 00242 template<typename T> T as() const //[t45] 00243 { 00244 T Obj; 00245 const bool NotNull = to(Obj); 00246 if (!NotNull) throw PGSTD::domain_error("Attempt to read null field"); 00247 return Obj; 00248 } 00249 00250 bool is_null() const { return m_Home->GetIsNull(m_Index,m_Col); } //[t12] 00251 00252 size_type size() const { return m_Home->GetLength(m_Index,m_Col); } //[t11] 00253 00254 #ifdef PQXX_DEPRECATED_HEADERS 00255 00256 const char *Name() const {return name();} 00257 #endif 00258 00259 private: 00260 tuple::size_type m_Col; 00261 }; 00262 00264 00268 class PQXX_LIBEXPORT const_iterator : 00269 public PGSTD::iterator<PGSTD::random_access_iterator_tag, 00270 const tuple, 00271 result::size_type>, 00272 public tuple 00273 { 00274 public: 00275 const_iterator() : tuple(0,0) {} 00276 00283 pointer operator->() const { return this; } //[t12] 00284 reference operator*() const { return *operator->(); } //[t12] 00285 00286 const_iterator operator++(int); //[t12] 00287 const_iterator &operator++() { ++m_Index; return *this; } //[t1] 00288 const_iterator operator--(int); //[t12] 00289 const_iterator &operator--() { --m_Index; return *this; } //[t12] 00290 00291 const_iterator &operator+=(difference_type i) //[t12] 00292 { m_Index+=i; return *this; } 00293 const_iterator &operator-=(difference_type i) //[t12] 00294 { m_Index-=i; return *this; } 00295 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 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 00309 inline const_iterator operator+(difference_type o) const; //[t12] 00310 00311 friend const_iterator operator+(difference_type o, 00312 const_iterator i); //[t12] 00313 00314 inline const_iterator operator-(difference_type o) const; //[t12] 00315 00316 inline difference_type operator-(const_iterator i) const; //[t12] 00317 00318 result::size_type num() const { return rownumber(); } //[t1] 00319 00320 private: 00321 friend class result; 00322 const_iterator(const result *r, result::size_type i) : tuple(r, i) {} 00323 }; 00324 00325 #ifdef PQXX_HAVE_REVERSE_ITERATOR 00326 typedef PGSTD::reverse_iterator<const_iterator> const_reverse_iterator; 00327 const_reverse_iterator rbegin() const //[t75] 00328 { return const_reverse_iterator(end()); } 00329 const_reverse_iterator rend() const //[t75] 00330 { return const_reverse_iterator(begin()); } 00331 #endif 00332 00333 const_iterator begin() const { return const_iterator(this, 0); } //[t1] 00334 inline const_iterator end() const; //[t1] 00335 00336 size_type size() const { return m_Result ? PQntuples(m_Result) : 0; } //[t2] 00337 bool empty() const { return !m_Result || !PQntuples(m_Result); } //[t11] 00338 size_type capacity() const { return size(); } //[t20] 00339 00340 void swap(result &other) throw (); //[t77] 00341 00342 const tuple operator[](size_type i) const throw () //[t2] 00343 { return tuple(this, i); } 00344 const tuple at(size_type) const throw (PGSTD::out_of_range); //[t10] 00345 00346 void clear() throw () { LoseRef(); } //[t20] 00347 00349 tuple::size_type columns() const throw () //[t11] 00350 { return PQnfields(m_Result); } 00351 00353 tuple::size_type column_number(const char ColName[]) const; //[t11] 00354 00356 tuple::size_type column_number(const PGSTD::string &Name) const //[t11] 00357 {return column_number(Name.c_str());} 00358 00360 const char *column_name(tuple::size_type Number) const; //[t11] 00361 00363 inline oid column_type(tuple::size_type ColNum) const; //[t7] 00364 00366 oid column_type(const PGSTD::string &ColName) const //[t7] 00367 { return column_type(column_number(ColName)); } 00368 00370 oid column_type(const char ColName[]) const //[t7] 00371 { return column_type(column_number(ColName)); } 00372 00373 #ifdef PQXX_HAVE_PQFTABLE 00374 00375 oid column_table(tuple::size_type ColNum) const; //[t2] 00376 00378 oid column_table(const PGSTD::string &ColName) const //[t2] 00379 { return column_table(column_number(ColName)); } 00380 #endif 00381 00383 00385 oid inserted_oid() const { return PQoidValue(m_Result); } //[t13] 00386 00387 00389 /*** Returns zero for all other commands. */ 00390 size_type affected_rows() const; //[t7] 00391 00392 00393 #ifdef PQXX_DEPRECATED_HEADERS 00395 typedef tuple Tuple; 00397 typedef field Field; 00399 oid InsertedOid() const { return inserted_oid(); } 00401 size_type AffectedRows() const { return affected_rows(); } 00403 tuple::size_type Columns() const { return columns(); } 00405 tuple::size_type ColumnNumber(const char Name[]) const 00406 {return PQfnumber(m_Result,Name);} 00408 tuple::size_type ColumnNumber(const PGSTD::string &Name) const 00409 {return ColumnNumber(Name.c_str());} 00411 const char *ColumnName(tuple::size_type Number) const 00412 {return PQfname(m_Result,Number);} 00413 #endif 00414 00415 00416 private: 00417 PGresult *m_Result; 00418 mutable int *m_Refcount; 00419 00420 friend class result::field; 00421 const char *GetValue(size_type Row, tuple::size_type Col) const; 00422 bool GetIsNull(size_type Row, tuple::size_type Col) const; 00423 field::size_type GetLength(size_type Row, tuple::size_type Col) const; 00424 00425 friend class connection_base; 00426 explicit result(PGresult *rhs) : m_Result(rhs), m_Refcount(0) {MakeRef(rhs);} 00427 result &operator=(PGresult *); 00428 bool operator!() const throw () { return !m_Result; } 00429 operator bool() const throw () { return m_Result != 0; } 00430 friend class pipeline; 00431 void CheckStatus(const PGSTD::string &Query) const; 00432 void CheckStatus(const char Query[]) const; 00433 int errorposition() const throw (); 00434 PGSTD::string StatusError() const; 00435 00436 friend class Cursor; 00437 const char *CmdStatus() const throw () { return PQcmdStatus(m_Result); } 00438 00439 00440 void MakeRef(PGresult *); 00441 void MakeRef(const result &) throw (); 00442 void LoseRef() throw (); 00443 }; 00444 00445 00447 00464 template<typename STREAM> 00465 inline STREAM &operator<<(STREAM &S, const pqxx::result::field &F) //[t46] 00466 { 00467 S.write(F.c_str(), F.size()); 00468 return S; 00469 } 00470 00471 00473 template<typename T> 00474 inline void from_string(const result::field &F, T &Obj) //[t46] 00475 { from_string(F.c_str(), Obj); } 00476 00478 template<> 00479 inline PGSTD::string to_string(const result::field &Obj) //[t74] 00480 { return to_string(Obj.c_str()); } 00481 00482 inline result::field 00483 result::tuple::operator[](result::tuple::size_type i) const throw () 00484 { 00485 return field(*this, i); 00486 } 00487 00488 inline result::tuple::size_type result::tuple::size() const throw () 00489 { 00490 return m_Home->columns(); 00491 } 00492 00493 inline const char *result::field::name() const 00494 { 00495 return m_Home->column_name(m_Col); 00496 } 00497 00499 template<> 00500 inline bool result::field::to<PGSTD::string>(PGSTD::string &Obj) const 00501 { 00502 if (is_null()) return false; 00503 Obj = c_str(); 00504 return true; 00505 } 00506 00508 00511 template<> 00512 inline bool result::field::to<const char *>(const char *&Obj) const 00513 { 00514 if (is_null()) return false; 00515 Obj = c_str(); 00516 return true; 00517 } 00518 00519 00520 inline result::const_iterator 00521 result::const_iterator::operator+(difference_type o) const 00522 { 00523 return const_iterator(m_Home, m_Index + o); 00524 } 00525 00526 inline result::const_iterator 00527 operator+(result::const_iterator::difference_type o, 00528 result::const_iterator i) 00529 { 00530 return i + o; 00531 } 00532 00533 inline result::const_iterator 00534 result::const_iterator::operator-(difference_type o) const 00535 { 00536 return const_iterator(m_Home, m_Index - o); 00537 } 00538 00539 inline result::const_iterator::difference_type 00540 result::const_iterator::operator-(const_iterator i) const 00541 { 00542 return num()-i.num(); 00543 } 00544 00545 inline result::const_iterator result::end() const 00546 { 00547 return const_iterator(this, size()); 00548 } 00549 00550 inline oid result::column_type(tuple::size_type ColNum) const 00551 { 00552 const oid T = PQftype(m_Result, ColNum); 00553 if (T == oid_none) 00554 throw PGSTD::invalid_argument( 00555 "Attempt to retrieve type of nonexistant column " + 00556 to_string(ColNum) + " " 00557 "of query result"); 00558 return T; 00559 } 00560 00561 00562 #ifdef PQXX_HAVE_PQFTABLE 00563 inline oid result::column_table(tuple::size_type ColNum) const 00564 { 00565 const oid T = PQftable(m_Result, ColNum); 00566 00567 /* If we get InvalidOid, it may be because the column is computed, or because 00568 * we got an invalid row number. 00569 */ 00570 // TODO: Skip this if we first computed the column name ourselves 00571 if ((T == InvalidOid) && 00572 ((ColNum < 0) || (ColNum >= columns()))) 00573 throw PGSTD::invalid_argument("Attempt to retrieve table ID for column " + 00574 to_string(ColNum) + " " 00575 "out of " + to_string(columns())); 00576 return T; 00577 } 00578 #endif 00579 00580 00581 template<typename CHAR=char, typename TRAITS=PGSTD::char_traits<CHAR> > 00582 class field_streambuf : 00583 #ifdef PQXX_HAVE_STREAMBUF 00584 public PGSTD::basic_streambuf<CHAR, TRAITS> 00585 #else 00586 public PGSTD::streambuf 00587 #endif 00588 { 00589 typedef long size_type; 00590 public: 00591 typedef CHAR char_type; 00592 typedef TRAITS traits_type; 00593 typedef typename traits_type::int_type int_type; 00594 #ifdef PQXX_HAVE_STREAMBUF 00595 typedef typename traits_type::pos_type pos_type; 00596 typedef typename traits_type::off_type off_type; 00597 #else 00598 typedef streamoff off_type; 00599 typedef streampos pos_type; 00600 #endif 00601 typedef PGSTD::ios::openmode openmode; 00602 typedef PGSTD::ios::seekdir seekdir; 00603 00604 explicit field_streambuf(const result::field &F) : //[t74] 00605 m_Field(F) 00606 { 00607 initialize(); 00608 } 00609 00610 #ifdef PQXX_HAVE_STREAMBUF 00611 protected: 00612 #endif 00613 virtual int sync() { return traits_type::eof(); } 00614 00615 protected: 00616 virtual pos_type seekoff(off_type, seekdir, openmode) 00617 { 00618 return traits_type::eof(); 00619 } 00620 00621 virtual pos_type seekpos(pos_type, openmode) {return traits_type::eof();} 00622 00623 virtual int_type overflow(int_type) { return traits_type::eof(); } 00624 00625 virtual int_type underflow() { return traits_type::eof(); } 00626 00627 private: 00628 const result::field &m_Field; 00629 00630 int_type initialize() throw () 00631 { 00632 char_type *G = 00633 reinterpret_cast<char_type *>(const_cast<char *>(m_Field.c_str())); 00634 setg(G, G, G + m_Field.size()); 00635 return m_Field.size(); 00636 } 00637 }; 00638 00639 00641 00655 template<typename CHAR=char, typename TRAITS=PGSTD::char_traits<CHAR> > 00656 class basic_fieldstream : 00657 #ifdef PQXX_HAVE_STREAMBUF 00658 public PGSTD::basic_istream<CHAR, TRAITS> 00659 #else 00660 public PGSTD::istream 00661 #endif 00662 { 00663 #ifdef PQXX_HAVE_STREAMBUF 00664 typedef PGSTD::basic_istream<CHAR, TRAITS> super; 00665 #else 00666 typedef PGSTD::istream super; 00667 #endif 00668 00669 public: 00670 typedef CHAR char_type; 00671 typedef TRAITS traits_type; 00672 typedef typename traits_type::int_type int_type; 00673 typedef typename traits_type::pos_type pos_type; 00674 typedef typename traits_type::off_type off_type; 00675 00676 basic_fieldstream(const result::field &F) : super(&m_Buf), m_Buf(F) { } 00677 00678 private: 00679 field_streambuf<CHAR, TRAITS> m_Buf; 00680 }; 00681 00682 typedef basic_fieldstream<char> fieldstream; 00683 00684 } // namespace pqxx 00685 00686 00687 00688 /* 00689 [1] Scott Meyers, in one of his essential books, "Effective C++" and "More 00690 Effective C++", points out that it is good style to have any class containing 00691 a member of pointer type define its own destructor--just to show that it knows 00692 what it is doing. This helps prevent nasty memory leak / double deletion bugs 00693 typically resulting from programmers' omission to deal with such issues in 00694 their destructors. 00695 00696 The -Weffc++ option in gcc generates warnings for noncompliance with Scott's 00697 style guidelines, and hence necessitates the definition of this destructor,\ 00698 trivial as it may be. 00699 00700 [2] IIRC Alex Stepanov, the inventor of the STL, once remarked that having 00701 this as standard behaviour for pointers would be useful in some algorithms. 00702 So even if this makes me look foolish, I would seem to be in distinguished 00703 company. 00704 */ 00705 00706

Generated on Sun Jun 6 20:55:10 2004 for libpqxx by doxygen 1.3.7