# 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"