libpqxx 4.0
transaction_base.hxx
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-2011, 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 #ifndef PQXX_H_TRANSACTION_BASE
00021 #define PQXX_H_TRANSACTION_BASE
00022 
00023 #include "pqxx/compiler-public.hxx"
00024 #include "pqxx/compiler-internal-pre.hxx"
00025 
00026 /* End-user programs need not include this file, unless they define their own
00027  * transaction classes.  This is not something the typical program should want
00028  * to do.
00029  *
00030  * However, reading this file is worthwhile because it defines the public
00031  * interface for the available transaction classes such as transaction and
00032  * nontransaction.
00033  */
00034 
00035 #include "pqxx/connection_base"
00036 #include "pqxx/isolation"
00037 #include "pqxx/result"
00038 
00039 /* Methods tested in eg. self-test program test001 are marked with "//[t1]"
00040  */
00041 
00042 namespace pqxx
00043 {
00044 class connection_base;
00045 class transaction_base;
00046 
00047 
00048 namespace internal
00049 {
00050 class sql_cursor;
00051 
00052 class PQXX_LIBEXPORT transactionfocus : public virtual namedclass
00053 {
00054 public:
00055   explicit transactionfocus(transaction_base &t) :
00056     namedclass("transactionfocus"),
00057     m_Trans(t),
00058     m_registered(false)
00059   {
00060   }
00061 
00062 protected:
00063   void register_me();
00064   void unregister_me() throw ();
00065   void reg_pending_error(const PGSTD::string &) throw ();
00066   bool registered() const throw () { return m_registered; }
00067 
00068   transaction_base &m_Trans;
00069 
00070 private:
00071   bool m_registered;
00072 
00074   transactionfocus();
00076   transactionfocus(const transactionfocus &);
00078   transactionfocus &operator=(const transactionfocus &);
00079 };
00080 
00081 
00082 class PQXX_LIBEXPORT parameterized_invocation : statement_parameters
00083 {
00084 public:
00085   parameterized_invocation(connection_base &, const PGSTD::string &query);
00086 
00087   parameterized_invocation &operator()() { add_param(); return *this; }
00088   parameterized_invocation &operator()(const binarystring &v)
00089         { add_binary_param(v, true); return *this; }
00090   template<typename T> parameterized_invocation &operator()(const T &v)
00091         { add_param(v, true); return *this; }
00092   parameterized_invocation &operator()(const binarystring &v, bool nonnull)
00093         { add_binary_param(v, nonnull); return *this; }
00094   template<typename T>
00095         parameterized_invocation &operator()(const T &v, bool nonnull)
00096         { add_param(v, nonnull); return *this; }
00097 
00098   result exec();
00099 
00100 private:
00102   parameterized_invocation &operator=(const parameterized_invocation &);
00103 
00104   connection_base &m_home;
00105   const PGSTD::string m_query;
00106 };
00107 } // namespace internal
00108 
00109 
00110 namespace internal
00111 {
00112 namespace gate
00113 {
00114 class transaction_subtransaction;
00115 class transaction_tablereader;
00116 class transaction_tablewriter;
00117 class transaction_transactionfocus;
00118 } // namespace internal::gate
00119 } // namespace internal
00120 
00121 
00123 
00133 class PQXX_LIBEXPORT PQXX_NOVTABLE transaction_base :
00134   public virtual internal::namedclass
00135 {
00136 public:
00138   typedef isolation_traits<read_committed> isolation_tag;
00139 
00140   virtual ~transaction_base() =0;                                       //[t1]
00141 
00143 
00155   void commit();                                                        //[t1]
00156 
00158 
00161   void abort();                                                         //[t10]
00162 
00167 
00168   PGSTD::string esc(const char str[]) const          { return conn().esc(str); }
00170   PGSTD::string esc(const char str[], size_t maxlen) const
00171                                              { return conn().esc(str, maxlen); }
00173   PGSTD::string esc(const PGSTD::string &str) const  { return conn().esc(str); }
00174 
00176 
00187   PGSTD::string esc_raw(const unsigned char str[], size_t len) const    //[t62]
00188                                             { return conn().esc_raw(str, len); }
00190   PGSTD::string esc_raw(const PGSTD::string &) const;                   //[t62]
00191 
00193 
00194   template<typename T> PGSTD::string quote(const T &t) const
00195                                                      { return conn().quote(t); }
00196 
00198   PGSTD::string quote_raw(const unsigned char str[], size_t len) const
00199                                           { return conn().quote_raw(str, len); }
00200 
00201   PGSTD::string quote_raw(const PGSTD::string &str) const;
00202 
00204   PGSTD::string quote_name(const PGSTD::string &identifier) const
00205                                        { return conn().quote_name(identifier); }
00207 
00209 
00224   result exec(const PGSTD::string &Query,
00225               const PGSTD::string &Desc=PGSTD::string());               //[t1]
00226 
00227   result exec(const PGSTD::stringstream &Query,
00228               const PGSTD::string &Desc=PGSTD::string())
00229         { return exec(Query.str(), Desc); }
00230 
00232   /* Use this to build up a parameterized statement invocation, then invoke it
00233    * using @c exec()
00234    *
00235    * Example: @c trans.parameterized("SELECT $1 + 1")(1).exec();
00236    */
00237   internal::parameterized_invocation parameterized(const PGSTD::string &query);
00238 
00243 
00244 
00288   prepare::invocation prepared(const PGSTD::string &statement=PGSTD::string());
00289 
00291 
00296 
00297   void process_notice(const char Msg[]) const                           //[t14]
00298         { m_Conn.process_notice(Msg); }
00300   void process_notice(const PGSTD::string &Msg) const                   //[t14]
00301         { m_Conn.process_notice(Msg); }
00303 
00305   connection_base &conn() const { return m_Conn; }                      //[t4]
00306 
00308 
00316   void set_variable(const PGSTD::string &Var, const PGSTD::string &Val);//[t61]
00317 
00319 
00328   PGSTD::string get_variable(const PGSTD::string &);                    //[t61]
00329 
00330 
00331 protected:
00333 
00339   explicit transaction_base(connection_base &c, bool direct=true);
00340 
00342 
00344   void Begin();
00345 
00347   void End() throw ();
00348 
00350   virtual void do_begin() =0;
00352   virtual result do_exec(const char Query[]) =0;
00354   virtual void do_commit() =0;
00356   virtual void do_abort() =0;
00357 
00358   // For use by implementing class:
00359 
00361 
00369   result DirectExec(const char C[], int Retries=0);
00370 
00372   void reactivation_avoidance_clear() throw ()
00373         {m_reactivation_avoidance.clear();}
00374 
00375 protected:
00377 
00379   internal::reactivation_avoidance_counter m_reactivation_avoidance;
00380 
00381 private:
00382   /* A transaction goes through the following stages in its lifecycle:
00383    * <ul>
00384    * <li> nascent: the transaction hasn't actually begun yet.  If our connection
00385    *    fails at this stage, it may recover and the transaction can attempt to
00386    *    establish itself again.
00387    * <li> active: the transaction has begun.  Since no commit command has been
00388    *    issued, abortion is implicit if the connection fails now.
00389    * <li> aborted: an abort has been issued; the transaction is terminated and
00390    *    its changes to the database rolled back.  It will accept no further
00391    *    commands.
00392    * <li> committed: the transaction has completed successfully, meaning that a
00393    *    commit has been issued.  No further commands are accepted.
00394    * <li> in_doubt: the connection was lost at the exact wrong time, and there
00395    *    is no way of telling whether the transaction was committed or aborted.
00396    * </ul>
00397    *
00398    * Checking and maintaining state machine logic is the responsibility of the
00399    * base class (ie., this one).
00400    */
00401   enum Status
00402   {
00403     st_nascent,
00404     st_active,
00405     st_aborted,
00406     st_committed,
00407     st_in_doubt
00408   };
00409 
00411   void PQXX_PRIVATE activate();
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 pqxx::internal::gate::transaction_transactionfocus;
00419   void PQXX_PRIVATE RegisterFocus(internal::transactionfocus *);
00420   void PQXX_PRIVATE UnregisterFocus(internal::transactionfocus *) throw ();
00421   void PQXX_PRIVATE RegisterPendingError(const PGSTD::string &) throw ();
00422 
00423   friend class pqxx::internal::gate::transaction_tablereader;
00424   void PQXX_PRIVATE BeginCopyRead(const PGSTD::string &, const PGSTD::string &);
00425   bool ReadCopyLine(PGSTD::string &);
00426 
00427   friend class pqxx::internal::gate::transaction_tablewriter;
00428   void PQXX_PRIVATE BeginCopyWrite(
00429         const PGSTD::string &Table,
00430         const PGSTD::string &Columns);
00431   void WriteCopyLine(const PGSTD::string &);
00432   void EndCopyWrite();
00433 
00434   friend class pqxx::internal::gate::transaction_subtransaction;
00435 
00436   connection_base &m_Conn;
00437 
00438   internal::unique<internal::transactionfocus> m_Focus;
00439   Status m_Status;
00440   bool m_Registered;
00441   PGSTD::map<PGSTD::string, PGSTD::string> m_Vars;
00442   PGSTD::string m_PendingError;
00443 
00445   transaction_base();
00447   transaction_base(const transaction_base &);
00449   transaction_base &operator=(const transaction_base &);
00450 };
00451 
00452 } // namespace pqxx
00453 
00454 
00455 #include "pqxx/compiler-internal-post.hxx"
00456 
00457 #endif
00458