libpqxx  3.1.1
transaction_base.hxx
1 /*-------------------------------------------------------------------------
2  *
3  * FILE
4  * pqxx/transaction_base.hxx
5  *
6  * DESCRIPTION
7  * common code and definitions for the transaction classes.
8  * pqxx::transaction_base defines the interface for any abstract class that
9  * represents a database transaction
10  * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/transaction_base instead.
11  *
12  * Copyright (c) 2001-2009, Jeroen T. Vermeulen <jtv@xs4all.nl>
13  *
14  * See COPYING for copyright license. If you did not receive a file called
15  * COPYING with this source code, please notify the distributor of this mistake,
16  * or contact the author.
17  *
18  *-------------------------------------------------------------------------
19  */
20 #ifndef PQXX_H_TRANSACTION_BASE
21 #define PQXX_H_TRANSACTION_BASE
22 
23 #include "pqxx/compiler-public.hxx"
24 #include "pqxx/compiler-internal-pre.hxx"
25 
26 /* End-user programs need not include this file, unless they define their own
27  * transaction classes. This is not something the typical program should want
28  * to do.
29  *
30  * However, reading this file is worthwhile because it defines the public
31  * interface for the available transaction classes such as transaction and
32  * nontransaction.
33  */
34 
35 #include "pqxx/connection_base"
36 #include "pqxx/isolation"
37 #include "pqxx/result"
38 
39 /* Methods tested in eg. self-test program test001 are marked with "//[t1]"
40  */
41 
42 namespace pqxx
43 {
44 class connection_base;
45 class transaction_base;
46 
47 
48 namespace internal
49 {
50 class sql_cursor;
51 
52 class PQXX_LIBEXPORT transactionfocus : public virtual namedclass
53 {
54 public:
56  namedclass("transactionfocus"),
57  m_Trans(t),
58  m_registered(false)
59  {
60  }
61 
62 protected:
63  void register_me();
64  void unregister_me() throw ();
65  void reg_pending_error(const PGSTD::string &) throw ();
66  bool registered() const throw () { return m_registered; }
67 
69 
70 private:
71  bool m_registered;
72 
78  transactionfocus &operator=(const transactionfocus &);
79 };
80 
81 
82 class PQXX_LIBEXPORT parameterized_invocation : statement_parameters
83 {
84 public:
85  parameterized_invocation(connection_base &, const PGSTD::string &query);
86 
87  parameterized_invocation &operator()() { add_param(); return *this; }
88  template<typename T> parameterized_invocation &operator()(const T &v)
89  { add_param(v); return *this; }
90  template<typename T>
91  parameterized_invocation &operator()(const T &v, bool nonnull)
92  { add_param(v, nonnull); return *this; }
93 
94  result exec();
95 
96 private:
99 
100  connection_base &m_home;
101  const PGSTD::string m_query;
102 };
103 } // namespace internal
104 
105 
106 namespace internal
107 {
108 namespace gate
109 {
110 class transaction_subtransaction;
111 class transaction_tablereader;
112 class transaction_tablewriter;
113 class transaction_transactionfocus;
114 } // namespace internal::gate
115 } // namespace internal
116 
117 
119 
129 class PQXX_LIBEXPORT PQXX_NOVTABLE transaction_base :
130  public virtual internal::namedclass
131 {
132 public:
135 
136  virtual ~transaction_base() =0; //[t1]
137 
139 
151  void commit(); //[t1]
152 
154 
157  void abort(); //[t10]
158 
163 
164  PGSTD::string esc(const char str[]) const //[t90]
165  { return m_Conn.esc(str); }
167  PGSTD::string esc(const char str[], size_t maxlen) const //[t90]
168  { return m_Conn.esc(str, maxlen); }
170  PGSTD::string esc(const PGSTD::string &str) const //[t90]
171  { return m_Conn.esc(str); }
172 
174 
185  PGSTD::string esc_raw(const unsigned char str[], size_t len) const //[t62]
186  { return m_Conn.esc_raw(str, len); }
188  PGSTD::string esc_raw(const PGSTD::string &) const; //[t62]
189 
191 
192  template<typename T> PGSTD::string quote(const T &t) const
193  { return m_Conn.quote(t); }
195 
197 
212  result exec(const PGSTD::string &Query,
213  const PGSTD::string &Desc=PGSTD::string()); //[t1]
214 
215  result exec(const PGSTD::stringstream &Query,
216  const PGSTD::string &Desc=PGSTD::string()) //[t9]
217  { return exec(Query.str(), Desc); }
218 
220  /* Use this to build up a parameterized statement invocation, then invoke it
221  * using @c exec()
222  *
223  * Example: @c trans.parameterized("SELECT $1 + 1")(1).exec();
224  */
225  internal::parameterized_invocation parameterized(const PGSTD::string &query);
226 
231 
232 
276  prepare::invocation prepared(const PGSTD::string &statement=PGSTD::string());
277 
279 
284 
285  void process_notice(const char Msg[]) const //[t14]
286  { m_Conn.process_notice(Msg); }
288  void process_notice(const PGSTD::string &Msg) const //[t14]
289  { m_Conn.process_notice(Msg); }
291 
293  connection_base &conn() const { return m_Conn; } //[t4]
294 
296 
304  void set_variable(const PGSTD::string &Var, const PGSTD::string &Val);//[t61]
305 
307 
316  PGSTD::string get_variable(const PGSTD::string &); //[t61]
317 
318 
319 protected:
321 
327  explicit transaction_base(connection_base &c, bool direct=true);
328 
330 
332  void Begin();
333 
335  void End() throw ();
336 
338  virtual void do_begin() =0;
340  virtual result do_exec(const char Query[]) =0;
342  virtual void do_commit() =0;
344  virtual void do_abort() =0;
345 
346  // For use by implementing class:
347 
349 
357  result DirectExec(const char C[], int Retries=0);
358 
360  void reactivation_avoidance_clear() throw ()
361  {m_reactivation_avoidance.clear();}
362 
363 protected:
365 
368 
369 private:
370  /* A transaction goes through the following stages in its lifecycle:
371  * <ul>
372  * <li> nascent: the transaction hasn't actually begun yet. If our connection
373  * fails at this stage, it may recover and the transaction can attempt to
374  * establish itself again.
375  * <li> active: the transaction has begun. Since no commit command has been
376  * issued, abortion is implicit if the connection fails now.
377  * <li> aborted: an abort has been issued; the transaction is terminated and
378  * its changes to the database rolled back. It will accept no further
379  * commands.
380  * <li> committed: the transaction has completed successfully, meaning that a
381  * commit has been issued. No further commands are accepted.
382  * <li> in_doubt: the connection was lost at the exact wrong time, and there
383  * is no way of telling whether the transaction was committed or aborted.
384  * </ul>
385  *
386  * Checking and maintaining state machine logic is the responsibility of the
387  * base class (ie., this one).
388  */
389  enum Status
390  {
391  st_nascent,
392  st_active,
393  st_aborted,
394  st_committed,
395  st_in_doubt
396  };
397 
399  void PQXX_PRIVATE activate();
400 
401  void PQXX_PRIVATE CheckPendingError();
402 
403  template<typename T> bool parm_is_null(T *p) const throw () { return !p; }
404  template<typename T> bool parm_is_null(T) const throw () { return false; }
405 
406  friend class pqxx::internal::gate::transaction_transactionfocus;
407  void PQXX_PRIVATE RegisterFocus(internal::transactionfocus *);
408  void PQXX_PRIVATE UnregisterFocus(internal::transactionfocus *) throw ();
409  void PQXX_PRIVATE RegisterPendingError(const PGSTD::string &) throw ();
410 
411  friend class pqxx::internal::gate::transaction_tablereader;
412  void PQXX_PRIVATE BeginCopyRead(const PGSTD::string &, const PGSTD::string &);
413  bool ReadCopyLine(PGSTD::string &);
414 
415  friend class pqxx::internal::gate::transaction_tablewriter;
416  void PQXX_PRIVATE BeginCopyWrite(
417  const PGSTD::string &Table,
418  const PGSTD::string &Columns);
419  void WriteCopyLine(const PGSTD::string &);
420  void EndCopyWrite();
421 
422  friend class pqxx::internal::gate::transaction_subtransaction;
423 
424  connection_base &m_Conn;
425 
426  internal::unique<internal::transactionfocus> m_Focus;
427  Status m_Status;
428  bool m_Registered;
429  PGSTD::map<PGSTD::string, PGSTD::string> m_Vars;
430  PGSTD::string m_PendingError;
431 
437  transaction_base &operator=(const transaction_base &);
438 };
439 
440 } // namespace pqxx
441 
442 
443 #include "pqxx/compiler-internal-post.hxx"
444 
445 #endif
446