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-2007, 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) =0;
00151 
00153 
00164   virtual result fetch(difference_type, difference_type &) =0;
00165 
00167 
00174   virtual difference_type move(difference_type) =0;
00175 
00177 
00183   virtual difference_type move(difference_type, difference_type &) =0;
00184 
00185   void close() throw ();                                                //[t3]
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)   //[t43]
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 
00451 typedef absolute_cursor<cursor_base::random_access, cursor_base::read_only>
00452         abscursor;
00453 
00454 class icursor_iterator;
00455 
00457 
00472 class PQXX_LIBEXPORT icursorstream :
00473   public basic_cursor<cursor_base::forward_only, cursor_base::read_only>
00474 {
00475   typedef basic_cursor<cursor_base::forward_only, cursor_base::read_only> super;
00476 public:
00478 
00489   icursorstream(transaction_base &Context,
00490       const PGSTD::string &Query,
00491       const PGSTD::string &Basename,
00492       difference_type Stride=1);                                        //[t81]
00493 
00495 
00517   icursorstream(transaction_base &Context,
00518       const result::field &Name,
00519       difference_type Stride=1);                                        //[t84]
00520 
00522 
00528   icursorstream &get(result &res) { res = fetchblock(); return *this; } //[t81]
00530 
00536   icursorstream &operator>>(result &res) { return get(res); }           //[t81]
00538 
00542   icursorstream &ignore(PGSTD::streamsize n=1);                         //[t81]
00543 
00545 
00548   void set_stride(difference_type stride);                              //[t81]
00549   difference_type stride() const throw () { return m_stride; }          //[t81]
00550 
00551 private:
00552   result fetchblock();
00553 
00554   friend class icursor_iterator;
00555   size_type forward(size_type n=1);
00556   void insert_iterator(icursor_iterator *) throw ();
00557   void remove_iterator(icursor_iterator *) const throw ();
00558 
00559   void service_iterators(size_type);
00560 
00561   difference_type m_stride;
00562   size_type m_realpos, m_reqpos;
00563 
00564   mutable icursor_iterator *m_iterators;
00565 };
00566 
00567 
00569 
00596 class PQXX_LIBEXPORT icursor_iterator :
00597   public PGSTD::iterator<PGSTD::input_iterator_tag,
00598         result,
00599         cursor_base::size_type,
00600         const result *,
00601         const result &>
00602 {
00603 public:
00604   typedef icursorstream istream_type;
00605   typedef istream_type::size_type size_type;
00606   typedef istream_type::difference_type difference_type;
00607 
00608   icursor_iterator() throw ();                                          //[t84]
00609   explicit icursor_iterator(istream_type &) throw ();                   //[t84]
00610   icursor_iterator(const icursor_iterator &) throw ();                  //[t84]
00611   ~icursor_iterator() throw ();
00612 
00613   const result &operator*() const { refresh(); return m_here; }         //[t84]
00614   const result *operator->() const { refresh(); return &m_here; }       //[t84]
00615   icursor_iterator &operator++();                                       //[t84]
00616   icursor_iterator operator++(int);                                     //[t84]
00617   icursor_iterator &operator+=(difference_type);                        //[t84]
00618   icursor_iterator &operator=(const icursor_iterator &) throw ();       //[t84]
00619 
00620   bool operator==(const icursor_iterator &rhs) const;                   //[t84]
00621   bool operator!=(const icursor_iterator &rhs) const throw ()           //[t84]
00622         { return !operator==(rhs); }
00623   bool operator<(const icursor_iterator &rhs) const;                    //[t84]
00624   bool operator>(const icursor_iterator &rhs) const                     //[t84]
00625         { return rhs < *this; }
00626   bool operator<=(const icursor_iterator &rhs) const                    //[t84]
00627         { return !(*this > rhs); }
00628   bool operator>=(const icursor_iterator &rhs) const                    //[t84]
00629         { return !(*this < rhs); }
00630 
00631 private:
00632   void refresh() const;
00633 
00634   friend class icursorstream;
00635   size_type pos() const throw () { return m_pos; }
00636   void fill(const result &);
00637 
00638   icursorstream *m_stream;
00639   result m_here;
00640   size_type m_pos;
00641   icursor_iterator *m_prev, *m_next;
00642 };
00643 
00644 
00645 } // namespace pqxx
00646 
00647 #include "pqxx/compiler-internal-post.hxx"

Generated on Thu Feb 1 17:12:08 2007 for libpqxx by  doxygen 1.5.1