cursor.hxx

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  *   FILE
00004  *      pqxx/cursor.hxx
00005  *
00006  *   DESCRIPTION
00007  *      definition of the iterator/container-style cursor classes
00008  *   C++-style wrappers for SQL cursors
00009  *   DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/pipeline instead.
00010  *
00011  * Copyright (c) 2004-2006, 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 "pqxx/compiler-public.hxx"
00020 #include "pqxx/compiler-internal-pre.hxx"
00021 
00022 #ifdef PQXX_HAVE_LIMITS
00023 #include <limits>
00024 #endif
00025 
00026 #include "pqxx/result"
00027 #include "pqxx/transaction_base"
00028 
00029 
00030 namespace pqxx
00031 {
00032 class dbtransaction;
00033 
00035 
00046 class PQXX_LIBEXPORT cursor_base
00047 {
00048 public:
00049   typedef result::size_type size_type;
00050   typedef result::difference_type difference_type;
00051 
00052   virtual ~cursor_base() throw () { close(); }
00053 
00055 
00058   enum accesspolicy
00059   {
00061     forward_only,
00063     random_access
00064   };
00065 
00067 
00070   enum updatepolicy
00071   {
00073     read_only,
00075     update
00076   };
00077 
00079 
00097   enum ownershippolicy
00098   {
00100     owned,
00102     loose
00103   };
00104 
00106 
00110   operator void *() const {return m_done ? 0 : m_context;}              //[t81]
00111 
00113 
00116   bool operator!() const { return m_done; }                             //[t81]
00117 
00122 
00123 
00126   static difference_type all() throw ();                                //[t81]
00128 
00130   static difference_type next() throw () { return 1; }                  //[t81]
00132 
00134   static difference_type prior() throw () { return -1; }                //[t0]
00136 
00138   static difference_type backward_all() throw ();                       //[t0]
00140 
00142 
00147   const PGSTD::string &name() const throw () { return m_name; }         //[t81]
00148 
00150   virtual result fetch(difference_type);                                //[]
00151 
00153 
00164   virtual result fetch(difference_type, difference_type &);             //[]
00165 
00167 
00174   virtual difference_type move(difference_type);                        //[]
00175 
00177 
00183   virtual difference_type move(difference_type, difference_type &);     //[]
00184 
00185   void close() throw ();                                                //[]
00186 
00187 protected:
00188   cursor_base(transaction_base *,
00189       const PGSTD::string &Name,
00190       bool embellish_name = true);
00191 
00192   void declare(const PGSTD::string &query,
00193       accesspolicy,
00194       updatepolicy,
00195       ownershippolicy,
00196       bool hold);
00197   void adopt(ownershippolicy);
00198 
00199   static PGSTD::string stridestring(difference_type);
00200   transaction_base *m_context;
00201   bool m_done;
00202 
00203   template<accesspolicy A> void check_displacement(difference_type) const { }
00204 
00205 #if defined(_MSC_VER)
00206   /* Visual C++ won't accept this specialization declaration unless it's in
00207    * here!  See below for the "standard" alternative.
00208    */
00209   template<>
00210     void check_displacement<cursor_base::forward_only>(difference_type) const;
00211 #endif
00212 
00213 private:
00214   PGSTD::string m_name;
00215   bool m_adopted;
00216   ownershippolicy m_ownership;
00217 
00218   struct cachedquery
00219   {
00220     difference_type dist;
00221     PGSTD::string query;
00222 
00223     cachedquery() : dist(0), query() {}
00224   };
00225   cachedquery m_lastfetch, m_lastmove;
00226 
00228   cursor_base();
00230   cursor_base(const cursor_base &);
00232   cursor_base &operator=(const cursor_base &);
00233 };
00234 
00235 /* Visual C++ demands that this specialization be declared inside the class,
00236  * which gcc claims is illegal.  There seems to be no single universally
00237  * accepted way to do this.
00238  */
00239 #if !defined(_MSC_VER)
00240 template<> void
00241   cursor_base::check_displacement<cursor_base::forward_only>(difference_type)
00242         const;
00243 #endif
00244 
00245 
00246 inline cursor_base::difference_type cursor_base::all() throw ()
00247 {
00248   // Microsoft Visual C++ sabotages numeric_limits by defining min() and max()
00249   // as preprocessor macros; some other compilers just don't have numeric_limits
00250 #if defined(PQXX_HAVE_LIMITS)
00251   return PGSTD::numeric_limits<difference_type>::max();
00252 #else
00253   return INT_MAX;
00254 #endif
00255 }
00256 
00257 inline cursor_base::difference_type cursor_base::backward_all() throw ()
00258 {
00259 #if defined(PQXX_HAVE_LIMITS)
00260   return PGSTD::numeric_limits<difference_type>::min() + 1;
00261 #else
00262   return INT_MIN + 1;
00263 #endif
00264 }
00265 
00266 
00267 // TODO: How do we work updates into the scheme?
00269 template<cursor_base::accesspolicy ACCESS, cursor_base::updatepolicy UPDATE>
00270 class basic_cursor : public cursor_base
00271 {
00272 public:
00274 
00284   basic_cursor(transaction_base *t,
00285       const PGSTD::string &query,
00286       const PGSTD::string &cname,
00287       ownershippolicy op=owned) :                                       //[t3]
00288     cursor_base(t, cname, true)
00289   {
00290     declare(query,
00291         ACCESS,
00292         UPDATE,
00293         op,
00294         op==loose || !dynamic_cast<dbtransaction *>(t));
00295   }
00296 
00298 
00306   basic_cursor(transaction_base *t,
00307       const PGSTD::string &cname,
00308       ownershippolicy op=owned) :                                       //[t45]
00309     cursor_base(t, cname, false)
00310   {
00311     adopt(op);
00312   }
00313 
00315 
00331   virtual result fetch(difference_type n)                               //[t3]
00332   {
00333     check_displacement<ACCESS>(n);
00334     return cursor_base::fetch(n);
00335   }
00336 
00337   virtual result fetch(difference_type n, difference_type &d)           //[t45]
00338   {
00339     check_displacement<ACCESS>(n);
00340     return cursor_base::fetch(n, d);
00341   }
00342 
00344 
00348   virtual difference_type move(difference_type n)                       //[t3]
00349   {
00350     check_displacement<ACCESS>(n);
00351     return cursor_base::move(n);
00352   }
00353 
00354   virtual difference_type move(difference_type n, difference_type &d)   //[t42]
00355   {
00356     check_displacement<ACCESS>(n);
00357     return cursor_base::move(n, d);
00358   }
00359 
00360   using cursor_base::close;
00361 };
00362 
00363 
00365 template<cursor_base::accesspolicy ACCESS, cursor_base::updatepolicy UPDATE>
00366 class absolute_cursor : public basic_cursor<ACCESS,UPDATE>
00367 {
00368   typedef basic_cursor<ACCESS,UPDATE> super;
00369 public:
00370   typedef cursor_base::size_type size_type;
00371   typedef cursor_base::difference_type difference_type;
00372 
00374 
00382   absolute_cursor(transaction_base *t,
00383       const PGSTD::string &query,
00384       const PGSTD::string &cname) :                                     //[t91]
00385     super(t, query, cname, cursor_base::owned),
00386     m_pos(0),
00387     m_size(0),
00388     m_size_known(false)
00389   {
00390   }
00391 
00392   virtual result fetch(difference_type n)                               //[t91]
00393   {
00394     difference_type m;
00395     return absolute_cursor::fetch(n, m);
00396   }
00397 
00398   virtual difference_type move(difference_type n)                       //[t91]
00399   {
00400     difference_type m;
00401     return move(n, m);
00402   }
00403 
00404   virtual difference_type move(difference_type d, difference_type &m)   //[]
00405   {
00406     const difference_type r(super::move(d, m));
00407     digest(d, m);
00408     return r;
00409   }
00410 
00411   virtual result fetch(difference_type d, difference_type &m)           //[t91]
00412   {
00413     const result r(super::fetch(d, m));
00414     digest(d, m);
00415     return r;
00416   }
00417 
00418   size_type pos() const throw () { return m_pos; }                      //[t91]
00419 
00420   difference_type move_to(cursor_base::size_type to)                    //[t91]
00421         { return move(difference_type(to)-difference_type(pos())); }
00422 
00423   difference_type move_to(cursor_base::size_type to,                    //[t91]
00424         cursor_base::difference_type &d)
00425         { return move(difference_type(to)-difference_type(pos()), d); }
00426 private:
00428   void digest(cursor_base::difference_type req,
00429       cursor_base::difference_type got) throw ()
00430   {
00431     m_pos += got;
00432 
00433     // This assumes that got < req can only happen if req < 0
00434     if (got < req && !m_size_known)
00435     {
00436       m_size = m_pos;
00437       m_size_known = true;
00438     }
00439   }
00440 
00441   cursor_base::size_type m_pos;
00442   cursor_base::size_type m_size;
00443   bool m_size_known;
00444 };
00445 
00446 
00448 typedef basic_cursor<cursor_base::random_access, cursor_base::read_only> cursor;
00449 
00450 
00451 class icursor_iterator;
00452 
00454 
00469 class PQXX_LIBEXPORT icursorstream :
00470   public basic_cursor<cursor_base::forward_only, cursor_base::read_only>
00471 {
00472   typedef basic_cursor<cursor_base::forward_only, cursor_base::read_only> super;
00473 public:
00475 
00486   icursorstream(transaction_base &Context,
00487       const PGSTD::string &Query,
00488       const PGSTD::string &Basename,
00489       difference_type Stride=1);                                        //[t81]
00490 
00492 
00514   icursorstream(transaction_base &Context,
00515       const result::field &Name,
00516       difference_type Stride=1);                                        //[t84]
00517 
00519 
00525   icursorstream &get(result &res) { res = fetchblock(); return *this; } //[t81]
00527 
00533   icursorstream &operator>>(result &res) { return get(res); }           //[t81]
00535 
00539   icursorstream &ignore(PGSTD::streamsize n=1);                         //[t81]
00540 
00542 
00545   void set_stride(difference_type stride);                              //[t81]
00546   difference_type stride() const throw () { return m_stride; }          //[t81]
00547 
00548 private:
00549   result fetchblock();
00550 
00551   friend class icursor_iterator;
00552   size_type forward(size_type n=1);
00553   void insert_iterator(icursor_iterator *) throw ();
00554   void remove_iterator(icursor_iterator *) const throw ();
00555 
00556   void service_iterators(size_type);
00557 
00558   difference_type m_stride;
00559   size_type m_realpos, m_reqpos;
00560 
00561   mutable icursor_iterator *m_iterators;
00562 };
00563 
00564 
00566 
00593 class PQXX_LIBEXPORT icursor_iterator :
00594   public PGSTD::iterator<PGSTD::input_iterator_tag,
00595         result,
00596         cursor_base::size_type,
00597         const result *,
00598         const result &>
00599 {
00600 public:
00601   typedef icursorstream istream_type;
00602   typedef istream_type::size_type size_type;
00603   typedef istream_type::difference_type difference_type;
00604 
00605   icursor_iterator() throw ();                                          //[t84]
00606   explicit icursor_iterator(istream_type &) throw ();                   //[t84]
00607   icursor_iterator(const icursor_iterator &) throw ();                  //[t84]
00608   ~icursor_iterator() throw ();
00609 
00610   const result &operator*() const { refresh(); return m_here; }         //[t84]
00611   const result *operator->() const { refresh(); return &m_here; }       //[t84]
00612   icursor_iterator &operator++();                                       //[t84]
00613   icursor_iterator operator++(int);                                     //[t84]
00614   icursor_iterator &operator+=(difference_type);                        //[t84]
00615   icursor_iterator &operator=(const icursor_iterator &) throw ();       //[t84]
00616 
00617   bool operator==(const icursor_iterator &rhs) const;                   //[t84]
00618   bool operator!=(const icursor_iterator &rhs) const throw ()           //[t84]
00619         { return !operator==(rhs); }
00620   bool operator<(const icursor_iterator &rhs) const;                    //[t84]
00621   bool operator>(const icursor_iterator &rhs) const                     //[t84]
00622         { return rhs < *this; }
00623   bool operator<=(const icursor_iterator &rhs) const                    //[t84]
00624         { return !(*this > rhs); }
00625   bool operator>=(const icursor_iterator &rhs) const                    //[t84]
00626         { return !(*this < rhs); }
00627 
00628 private:
00629   void refresh() const;
00630 
00631   friend class icursorstream;
00632   size_type pos() const throw () { return m_pos; }
00633   void fill(const result &);
00634 
00635   icursorstream *m_stream;
00636   result m_here;
00637   size_type m_pos;
00638   icursor_iterator *m_prev, *m_next;
00639 };
00640 
00641 
00642 } // namespace pqxx
00643 
00644 #include "pqxx/compiler-internal-post.hxx"

Generated on Wed Sep 6 16:54:12 2006 for libpqxx by  doxygen 1.4.7