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 { return m_Result ? PQntuples(m_Result) : 0; } //[t2] 00336 bool empty() const { return !m_Result || !PQntuples(m_Result); } //[t11] 00337 size_type capacity() const { return size(); } //[t20] 00338 00339 void swap(result &other) throw (); //[t77] 00340 00341 const tuple operator[](size_type i) const throw () //[t2] 00342 { return tuple(this, i); } 00343 const tuple at(size_type) const throw (PGSTD::out_of_range); //[t10] 00344 00345 void clear() throw () { LoseRef(); } //[t20] 00346 00348 tuple::size_type columns() const throw () //[t11] 00349 { return PQnfields(m_Result); } 00350 00352 tuple::size_type column_number(const char ColName[]) const; //[t11] 00353 00355 tuple::size_type column_number(const PGSTD::string &Name) const //[t11] 00356 {return column_number(Name.c_str());} 00357 00359 const char *column_name(tuple::size_type Number) const; //[t11] 00360 00362 inline oid column_type(tuple::size_type ColNum) const; //[t7] 00363 00365 oid column_type(const PGSTD::string &ColName) const //[t7] 00366 { return column_type(column_number(ColName)); } 00367 00369 oid column_type(const char ColName[]) const //[t7] 00370 { return column_type(column_number(ColName)); } 00371 00372 #ifdef PQXX_HAVE_PQFTABLE 00373 00374 oid column_table(tuple::size_type ColNum) const; //[t2] 00375 00377 oid column_table(const PGSTD::string &ColName) const //[t2] 00378 { return column_table(column_number(ColName)); } 00379 #endif 00380 00382 00384 oid inserted_oid() const { return PQoidValue(m_Result); } //[t13] 00385 00386 00388 /*** Returns zero for all other commands. */ 00389 size_type affected_rows() const; //[t7] 00390 00391 00392 #ifdef PQXX_DEPRECATED_HEADERS 00394 typedef tuple Tuple; 00396 typedef field Field; 00398 oid InsertedOid() const { return inserted_oid(); } 00400 size_type AffectedRows() const { return affected_rows(); } 00402 tuple::size_type Columns() const { return columns(); } 00404 tuple::size_type ColumnNumber(const char Name[]) const 00405 {return PQfnumber(m_Result,Name);} 00407 tuple::size_type ColumnNumber(const PGSTD::string &Name) const 00408 {return ColumnNumber(Name.c_str());} 00410 const char *ColumnName(tuple::size_type Number) const 00411 {return PQfname(m_Result,Number);} 00412 #endif 00413 00414 00415 private: 00416 PGresult *m_Result; 00417 mutable const result *m_l, *m_r; 00418 00419 friend class result::field; 00420 const char *GetValue(size_type Row, tuple::size_type Col) const; 00421 bool GetIsNull(size_type Row, tuple::size_type Col) const; 00422 field::size_type GetLength(size_type Row, tuple::size_type Col) const; 00423 00424 friend class connection_base; 00425 friend class pipeline; 00426 explicit result(PGresult *rhs) throw () : 00427 m_Result(0), m_l(this), m_r(this) {MakeRef(rhs);} 00428 result &operator=(PGresult *) throw (); 00429 bool operator!() const throw () { return !m_Result; } 00430 operator bool() const throw () { return m_Result != 0; } 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 *) throw (); 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 Fri Jul 2 21:47:28 2004 for libpqxx by doxygen 1.3.7