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

Generated on Sat Aug 21 03:39:32 2004 for libpqxx by doxygen 1.3.8