Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

transaction_base.hxx

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  *   FILE
00004  *      pqxx/transaction_base.hxx
00005  *
00006  *   DESCRIPTION
00007  *      common code and definitions for the transaction classes.
00008  *   pqxx::transaction_base defines the interface for any abstract class that
00009  *   represents a database transaction
00010  *   DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/transaction_base instead.
00011  *
00012  * Copyright (c) 2001-2005, Jeroen T. Vermeulen <jtv@xs4all.nl>
00013  *
00014  * See COPYING for copyright license.  If you did not receive a file called
00015  * COPYING with this source code, please notify the distributor of this mistake,
00016  * or contact the author.
00017  *
00018  *-------------------------------------------------------------------------
00019  */
00020 #include "pqxx/libcompiler.h"
00021 
00022 /* End-user programs need not include this file, unless they define their own
00023  * transaction classes.  This is not something the typical program should want
00024  * to do.
00025  *
00026  * However, reading this file is worthwhile because it defines the public
00027  * interface for the available transaction classes such as transaction and
00028  * nontransaction.
00029  */
00030 
00031 #include "pqxx/connection_base"
00032 #include "pqxx/isolation"
00033 #include "pqxx/result"
00034 
00035 /* Methods tested in eg. self-test program test001 are marked with "//[t1]"
00036  */
00037 
00038 // TODO: Any way the BEGIN and the first query can be concatenated/pipelined?
00039 
00040 namespace pqxx
00041 {
00042 class connection_base;
00043 class transaction_base;
00044 
00045 
00046 namespace internal
00047 {
00048 class PQXX_LIBEXPORT transactionfocus : public namedclass
00049 {
00050 public:
00051   transactionfocus(transaction_base &t,
00052       const PGSTD::string &Name,
00053       const PGSTD::string &Classname) :
00054     namedclass(Name, Classname),
00055     m_Trans(t),
00056     m_registered(false)
00057   {
00058   }
00059 
00060 protected:
00061   void register_me();
00062   void unregister_me() throw ();
00063   void reg_pending_error(const PGSTD::string &) throw ();
00064   bool registered() const throw () { return m_registered; }
00065 
00066   transaction_base &m_Trans;
00067 
00068 private:
00069   bool m_registered;
00070 
00072   transactionfocus();
00074   transactionfocus(const transactionfocus &);
00076   transactionfocus &operator=(const transactionfocus &);
00077 };
00078 } // namespace internal
00079 
00080 
00081 
00083 
00093 class PQXX_LIBEXPORT transaction_base : public internal::namedclass
00094 {
00095 public:
00097   typedef isolation_traits<read_committed> isolation_tag;
00098 
00099   virtual ~transaction_base() =0;                                       //[t1]
00100 
00102 
00114   void commit();                                                        //[t1]
00115 
00117 
00120   void abort();                                                         //[t10]
00121 
00123 
00128   result exec(const char Query[],
00129               const PGSTD::string &Desc=PGSTD::string());               //[t1]
00130 
00132 
00140   result exec(const PGSTD::string &Query,
00141               const PGSTD::string &Desc=PGSTD::string())                //[t2]
00142         { return exec(Query.c_str(), Desc); }
00143 
00144   result exec(const PGSTD::stringstream &Query,
00145               const PGSTD::string &Desc=PGSTD::string())                //[t9]
00146         { return exec(Query.str(), Desc); }
00147 
00152 
00153 
00168   result exec_prepared(const PGSTD::string &qname)                      //[t85]
00169         { return m_Conn.pq_exec_prepared(qname.c_str(), 0, 0); }
00170 
00172 
00187   result exec_prepared(const char qname[])                              //[t85]
00188         { return m_Conn.pq_exec_prepared(qname, 0, 0); }
00189 
00191 
00209   template<typename STRING, typename ITER>
00210     result exec_prepared(STRING qname, ITER beginargs, ITER endargs)    //[t85]
00211   {
00212     if (beginargs == endargs) return exec_prepared(qname);
00213 
00214     typedef PGSTD::vector<PGSTD::string> pvec;
00215     pvec p;
00216     PGSTD::vector<bool> nulls;
00217     for (; beginargs!=endargs; ++beginargs)
00218     {
00219       const bool isnull = parm_is_null(*beginargs);
00220       nulls.push_back(isnull);
00221       p.push_back(to_string(isnull ? "" : *beginargs));
00222     }
00223     result r;
00224     const internal::scoped_array<const char *> pindex(p.size()+1);
00225     const pvec::size_type stop = p.size();
00226     for (pvec::size_type i=0; i < stop; ++i)
00227       pindex[i] = (nulls[i] ? 0 : p[i].c_str());
00228     pindex[stop] = 0;
00229     r = m_Conn.pq_exec_prepared(qname, p.size(), pindex.c_ptr());
00230     return r;
00231   }
00232 
00234 
00249   template<typename CNTNR> result exec_prepared(const char qname[],     //[t85]
00250       const CNTNR &args)
00251         { return exec_prepared(qname, args.begin(), args.end()); }
00252 
00254 
00269   template<typename CNTNR>
00270     result exec_prepared(const PGSTD::string &qname, CNTNR args)        //[t85]
00271         { return exec_prepared(qname, args.begin(), args.end()); }
00273 
00278 
00279   void process_notice(const char Msg[]) const                           //[t14]
00280         { m_Conn.process_notice(Msg); }
00282   void process_notice(const PGSTD::string &Msg) const                   //[t14]
00283         { m_Conn.process_notice(Msg); }
00285 
00287   connection_base &conn() const { return m_Conn; }                      //[t4]
00288 
00290 
00298   void set_variable(const PGSTD::string &Var, const PGSTD::string &Val);//[t61]
00299 
00301 
00310   PGSTD::string get_variable(const PGSTD::string &);                    //[t61]
00311 
00312 #ifdef PQXX_DEPRECATED_HEADERS
00313 
00317 
00318   void Commit() { commit(); }
00320   void Abort() { abort(); }
00322   result Exec(const char Q[], const PGSTD::string &D=PGSTD::string())
00323         { return exec(Q,D); }
00325   result Exec(const PGSTD::string &Q, const PGSTD::string &D=PGSTD::string())
00326         { return exec(Q,D); }
00328   void ProcessNotice(const char M[]) const { return process_notice(M); }
00330   void ProcessNotice(const PGSTD::string &M) const { return process_notice(M); }
00332   PGSTD::string Name() const { return name(); }
00334   connection_base &Conn() const { return conn(); }
00336   void SetVariable(const PGSTD::string &Var, const PGSTD::string &Val)
00337         { set_variable(Var,Val); }
00339 #endif
00340 
00341 protected:
00343 
00346   explicit transaction_base(connection_base &,
00347                           const PGSTD::string &TName,
00348                           const PGSTD::string &CName);
00349 
00351 
00353   void Begin();
00354 
00356   void End() throw ();
00357 
00359   virtual void do_begin() =0;
00361   virtual result do_exec(const char Query[]) =0;
00363   virtual void do_commit() =0;
00365   virtual void do_abort() =0;
00366 
00367   // For use by implementing class:
00368 
00370 
00378   result DirectExec(const char C[], int Retries=0);
00379 
00381   void reactivation_avoidance_clear() throw () { m_reactivation_avoidance = 0; }
00382 
00383 private:
00384   /* A transaction goes through the following stages in its lifecycle:
00385    * <ul>
00386    * <li> nascent: the transaction hasn't actually begun yet.  If our connection
00387    *    fails at this stage, it may recover and the transaction can attempt to
00388    *    establish itself again.
00389    * <li> active: the transaction has begun.  Since no commit command has been
00390    *    issued, abortion is implicit if the connection fails now.
00391    * <li> aborted: an abort has been issued; the transaction is terminated and
00392    *    its changes to the database rolled back.  It will accept no further
00393    *    commands.
00394    * <li> committed: the transaction has completed successfully, meaning that a
00395    *    commit has been issued.  No further commands are accepted.
00396    * <li> in_doubt: the connection was lost at the exact wrong time, and there
00397    *    is no way of telling whether the transaction was committed or aborted.
00398    * </ul>
00399    *
00400    * Checking and maintaining state machine logic is the responsibility of the
00401    * base class (ie., this one).
00402    */
00403   enum Status
00404   {
00405     st_nascent,
00406     st_active,
00407     st_aborted,
00408     st_committed,
00409     st_in_doubt
00410   };
00411 
00412 
00413   void PQXX_PRIVATE CheckPendingError();
00414 
00415   template<typename T> bool parm_is_null(T *p) const throw () { return !p; }
00416   template<typename T> bool parm_is_null(T) const throw () { return false; }
00417 
00418   friend class Cursor;
00419   friend class cursor_base;
00420   int GetUniqueCursorNum() { return m_UniqueCursorNum++; }
00421   void MakeEmpty(result &R) const { m_Conn.MakeEmpty(R); }
00422   void reactivation_avoidance_inc() throw () { ++m_reactivation_avoidance; }
00423   void reactivation_avoidance_dec() throw () { --m_reactivation_avoidance; }
00424 
00425   friend class internal::transactionfocus;
00426   void PQXX_PRIVATE RegisterFocus(internal::transactionfocus *);
00427   void PQXX_PRIVATE UnregisterFocus(internal::transactionfocus *) throw ();
00428   void PQXX_PRIVATE RegisterPendingError(const PGSTD::string &) throw ();
00429   friend class tablereader;
00430   void PQXX_PRIVATE BeginCopyRead(const PGSTD::string &, const PGSTD::string &);
00431   bool ReadCopyLine(PGSTD::string &L) { return m_Conn.ReadCopyLine(L); }
00432   friend class tablewriter;
00433   void PQXX_PRIVATE BeginCopyWrite(const PGSTD::string &Table,
00434         const PGSTD::string &Columns = PGSTD::string());
00435   void WriteCopyLine(const PGSTD::string &L) { m_Conn.WriteCopyLine(L); }
00436   void EndCopyWrite() { m_Conn.EndCopyWrite(); }
00437 
00438   friend class pipeline;
00439   void start_exec(const PGSTD::string &Q) { m_Conn.start_exec(Q); }
00440   internal::pq::PGresult *get_result() { return m_Conn.get_result(); }
00441   void consume_input() throw () { m_Conn.consume_input(); }
00442   bool is_busy() const throw () { return m_Conn.is_busy(); }
00443 
00444   connection_base &m_Conn;
00445 
00446   int m_UniqueCursorNum;
00447   internal::unique<internal::transactionfocus> m_Focus;
00448   Status m_Status;
00449   bool m_Registered;
00450   PGSTD::map<PGSTD::string, PGSTD::string> m_Vars;
00451   PGSTD::string m_PendingError;
00453 
00455   int m_reactivation_avoidance;
00456 
00458   transaction_base();
00460   transaction_base(const transaction_base &);
00462   transaction_base &operator=(const transaction_base &);
00463 };
00464 
00465 } // namespace pqxx
00466 
00467 

Generated on Mon Oct 3 20:28:59 2005 for libpqxx by  doxygen 1.4.2