libpqxx  4.0.1
transactor.hxx
1 /*-------------------------------------------------------------------------
2  *
3  * FILE
4  * pqxx/transactor.hxx
5  *
6  * DESCRIPTION
7  * definition of the pqxx::transactor class.
8  * pqxx::transactor is a framework-style wrapper for safe transactions
9  * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/transactor instead.
10  *
11  * Copyright (c) 2001-2008, Jeroen T. Vermeulen <jtv@xs4all.nl>
12  *
13  * See COPYING for copyright license. If you did not receive a file called
14  * COPYING with this source code, please notify the distributor of this mistake,
15  * or contact the author.
16  *
17  *-------------------------------------------------------------------------
18  */
19 #ifndef PQXX_H_TRANSACTOR
20 #define PQXX_H_TRANSACTOR
21 
22 #include "pqxx/compiler-public.hxx"
23 #include "pqxx/compiler-internal-pre.hxx"
24 
25 #include "pqxx/connection_base"
26 #include "pqxx/transaction"
27 
28 
29 /* Methods tested in eg. self-test program test001 are marked with "//[t1]"
30  */
31 
32 namespace pqxx
33 {
34 
36 
65 template<typename TRANSACTION=transaction<read_committed> >
66  class transactor :
67  public PGSTD::unary_function<TRANSACTION, void>
68 {
69 public:
70  explicit transactor(const PGSTD::string &TName="transactor") : //[t4]
71  m_Name(TName) { }
72 
74 
85  void operator()(TRANSACTION &T); //[t4]
86 
87  // Overridable member functions, called by connection_base::perform() if an
88  // attempt to run transaction fails/succeeds, respectively, or if the
89  // connection is lost at just the wrong moment, goes into an indeterminate
90  // state. Use these to patch up runtime state to match events, if needed, or
91  // to report failure conditions.
92 
94 
102  void on_abort(const char[]) throw () {} //[t13]
103 
105 
109  void on_commit() {} //[t7]
110 
112 
123  void on_doubt() throw () {} //[t13]
124 
125  // TODO: Rename Name()--is there a compatible way?
127  PGSTD::string Name() const { return m_Name; } //[t13]
128 
129 private:
130  PGSTD::string m_Name;
131 };
132 
133 
134 }
135 
136 
137 template<typename TRANSACTOR>
138 inline void pqxx::connection_base::perform(const TRANSACTOR &T,
139  int Attempts)
140 {
141  if (Attempts <= 0) return;
142 
143  bool Done = false;
144 
145  // Make attempts to perform T
146  // TODO: Differentiate between db-related exceptions and other exceptions?
147  do
148  {
149  --Attempts;
150 
151  // Work on a copy of T2 so we can restore the starting situation if need be
152  TRANSACTOR T2(T);
153  try
154  {
155  typename TRANSACTOR::argument_type X(*this, T2.Name());
156  T2(X);
157  X.commit();
158  Done = true;
159  }
160  catch (const in_doubt_error &)
161  {
162  // Not sure whether transaction went through or not. The last thing in
163  // the world that we should do now is retry.
164  T2.on_doubt();
165  throw;
166  }
167  catch (const PGSTD::exception &e)
168  {
169  // Could be any kind of error.
170  T2.on_abort(e.what());
171  if (Attempts <= 0) throw;
172  continue;
173  }
174  catch (...)
175  {
176  // Don't try to forge ahead if we don't even know what happened
177  T2.on_abort("Unknown exception");
178  throw;
179  }
180 
181  T2.on_commit();
182  } while (!Done);
183 }
184 
185 
186 #include "pqxx/compiler-internal-post.hxx"
187 
188 #endif
189