libpqxx 4.0
|
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() {} //[t7] 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