# transactor.hxx

    00001 /*-------------------------------------------------------------------------
    00002  *
    00003  *   FILE
    00004  *      pqxx/transactor.hxx
    00005  *
    00006  *   DESCRIPTION
    00007  *      definition of the pqxx::transactor class.
    00008  *   pqxx::transactor is a framework-style wrapper for safe transactions
    00009  *   DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/transactor instead.
    00010  *
    00011  * Copyright (c) 2001-2008, 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 #ifndef PQXX_H_TRANSACTOR
    00020 #define PQXX_H_TRANSACTOR
    00021
    00022 #include "pqxx/compiler-public.hxx"
    00023 #include "pqxx/compiler-internal-pre.hxx"
    00024
    00025 #include "pqxx/connection_base"
    00026 #include "pqxx/transaction"
    00027
    00028
    00029 /* Methods tested in eg. self-test program test001 are marked with "//[t1]"
    00030  */
    00031
    00032 namespace pqxx
    00033 {
    00034
    00036
    00065 template<typename TRANSACTION=transaction<read_committed> >
    00066   class transactor :
    00067     public PGSTD::unary_function<TRANSACTION, void>
    00068 {
    00069 public:
    00070   explicit transactor(const PGSTD::string &TName="transactor") :        //[t4]
    00071     m_Name(TName) { }
    00072
    00074
    00085   void operator()(TRANSACTION &T);                                      //[t4]
    00086
    00087   // Overridable member functions, called by connection_base::perform() if an
    00088   // attempt to run transaction fails/succeeds, respectively, or if the
    00089   // connection is lost at just the wrong moment, goes into an indeterminate
    00090   // state.  Use these to patch up runtime state to match events, if needed, or
    00091   // to report failure conditions.
    00092
    00094
    00102   void on_abort(const char[]) throw () {}                               //[t13]
    00103
    00105
    00109   void on_commit() {}                                                   //[t6]
    00110
    00112
    00123   void on_doubt() throw () {}                                           //[t13]
    00124
    00125   // TODO: Rename Name()--is there a compatible way?
    00127   PGSTD::string Name() const { return m_Name; }                         //[t13]
    00128
    00129 private:
    00130   PGSTD::string m_Name;
    00131 };
    00132
    00133
    00134 }
    00135
    00136
    00137 template<typename TRANSACTOR>
    00138 inline void pqxx::connection_base::perform(const TRANSACTOR &T,
    00139                                            int Attempts)
    00140 {
    00141   if (Attempts <= 0) return;
    00142
    00143   bool Done = false;
    00144
    00145   // Make attempts to perform T
    00146   // TODO: Differentiate between db-related exceptions and other exceptions?
    00147   do
    00148   {
    00149     --Attempts;
    00150
    00151     // Work on a copy of T2 so we can restore the starting situation if need be
    00152     TRANSACTOR T2(T);
    00153     try
    00154     {
    00155       typename TRANSACTOR::argument_type X(*this, T2.Name());
    00156       T2(X);
    00157       X.commit();
    00158       Done = true;
    00159     }
    00160     catch (const in_doubt_error &)
    00161     {
    00162       // Not sure whether transaction went through or not.  The last thing in
    00163       // the world that we should do now is retry.
    00164       T2.on_doubt();
    00165       throw;
    00166     }
    00167     catch (const PGSTD::exception &e)
    00168     {
    00169       // Could be any kind of error.
    00170       T2.on_abort(e.what());
    00171       if (Attempts <= 0) throw;
    00172       continue;
    00173     }
    00174     catch (...)
    00175     {
    00176       // Don't try to forge ahead if we don't even know what happened
    00177       T2.on_abort("Unknown exception");
    00178       throw;
    00179     }
    00180
    00181     T2.on_commit();
    00182   } while (!Done);
    00183 }
    00184
    00185
    00186 #include "pqxx/compiler-internal-post.hxx"
    00187
    00188 #endif
    00189