libpqxx  4.0.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-2011, 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  parameterized_invocation &operator()(const binarystring &v)
89  { add_binary_param(v, true); return *this; }
90  template<typename T> parameterized_invocation &operator()(const T &v)
91  { add_param(v, true); return *this; }
92  parameterized_invocation &operator()(const binarystring &v, bool nonnull)
93  { add_binary_param(v, nonnull); return *this; }
94  template<typename T>
95  parameterized_invocation &operator()(const T &v, bool nonnull)
96  { add_param(v, nonnull); return *this; }
97 
98  result exec();
99 
100 private:
103 
104  connection_base &m_home;
105  const PGSTD::string m_query;
106 };
107 } // namespace internal
108 
109 
110 namespace internal
111 {
112 namespace gate
113 {
114 class transaction_subtransaction;
115 class transaction_tablereader;
116 class transaction_tablewriter;
117 class transaction_transactionfocus;
118 } // namespace internal::gate
119 } // namespace internal
120 
121 
123 
133 class PQXX_LIBEXPORT PQXX_NOVTABLE transaction_base :
134  public virtual internal::namedclass
135 {
136 public:
139 
140  virtual ~transaction_base() =0; //[t1]
141 
143 
155  void commit(); //[t1]
156 
158 
161  void abort(); //[t10]
162 
167 
168  PGSTD::string esc(const char str[]) const { return conn().esc(str); }
170  PGSTD::string esc(const char str[], size_t maxlen) const
171  { return conn().esc(str, maxlen); }
173  PGSTD::string esc(const PGSTD::string &str) const { return conn().esc(str); }
174 
176 
187  PGSTD::string esc_raw(const unsigned char str[], size_t len) const //[t62]
188  { return conn().esc_raw(str, len); }
190  PGSTD::string esc_raw(const PGSTD::string &) const; //[t62]
191 
193 
194  template<typename T> PGSTD::string quote(const T &t) const
195  { return conn().quote(t); }
196 
198  PGSTD::string quote_raw(const unsigned char str[], size_t len) const
199  { return conn().quote_raw(str, len); }
200 
201  PGSTD::string quote_raw(const PGSTD::string &str) const;
202 
204  PGSTD::string quote_name(const PGSTD::string &identifier) const
205  { return conn().quote_name(identifier); }
207 
209 
224  result exec(const PGSTD::string &Query,
225  const PGSTD::string &Desc=PGSTD::string()); //[t1]
226 
227  result exec(const PGSTD::stringstream &Query,
228  const PGSTD::string &Desc=PGSTD::string())
229  { return exec(Query.str(), Desc); }
230 
232  /* Use this to build up a parameterized statement invocation, then invoke it
233  * using @c exec()
234  *
235  * Example: @c trans.parameterized("SELECT $1 + 1")(1).exec();
236  */
237  internal::parameterized_invocation parameterized(const PGSTD::string &query);
238 
243 
244 
288  prepare::invocation prepared(const PGSTD::string &statement=PGSTD::string());
289 
291 
296 
297  void process_notice(const char Msg[]) const //[t14]
298  { m_Conn.process_notice(Msg); }
300  void process_notice(const PGSTD::string &Msg) const //[t14]
301  { m_Conn.process_notice(Msg); }
303 
305  connection_base &conn() const { return m_Conn; } //[t4]
306 
308 
316  void set_variable(const PGSTD::string &Var, const PGSTD::string &Val);//[t61]
317 
319 
328  PGSTD::string get_variable(const PGSTD::string &); //[t61]
329 
330 
331 protected:
333 
339  explicit transaction_base(connection_base &c, bool direct=true);
340 
342 
344  void Begin();
345 
347  void End() throw ();
348 
350  virtual void do_begin() =0;
352  virtual result do_exec(const char Query[]) =0;
354  virtual void do_commit() =0;
356  virtual void do_abort() =0;
357 
358  // For use by implementing class:
359 
361 
369  result DirectExec(const char C[], int Retries=0);
370 
372  void reactivation_avoidance_clear() throw ()
373  {m_reactivation_avoidance.clear();}
374 
375 protected:
377 
380 
381 private:
382  /* A transaction goes through the following stages in its lifecycle:
383  * <ul>
384  * <li> nascent: the transaction hasn't actually begun yet. If our connection
385  * fails at this stage, it may recover and the transaction can attempt to
386  * establish itself again.
387  * <li> active: the transaction has begun. Since no commit command has been
388  * issued, abortion is implicit if the connection fails now.
389  * <li> aborted: an abort has been issued; the transaction is terminated and
390  * its changes to the database rolled back. It will accept no further
391  * commands.
392  * <li> committed: the transaction has completed successfully, meaning that a
393  * commit has been issued. No further commands are accepted.
394  * <li> in_doubt: the connection was lost at the exact wrong time, and there
395  * is no way of telling whether the transaction was committed or aborted.
396  * </ul>
397  *
398  * Checking and maintaining state machine logic is the responsibility of the
399  * base class (ie., this one).
400  */
401  enum Status
402  {
403  st_nascent,
404  st_active,
405  st_aborted,
406  st_committed,
407  st_in_doubt
408  };
409 
411  void PQXX_PRIVATE activate();
412 
413  void PQXX_PRIVATE CheckPendingError();
414 
415  template<typename T> bool parm_is_null(T *p) const throw () { return !p; }
416  template<typename T> bool parm_is_null(T) const throw () { return false; }
417 
418  friend class pqxx::internal::gate::transaction_transactionfocus;
419  void PQXX_PRIVATE RegisterFocus(internal::transactionfocus *);
420  void PQXX_PRIVATE UnregisterFocus(internal::transactionfocus *) throw ();
421  void PQXX_PRIVATE RegisterPendingError(const PGSTD::string &) throw ();
422 
423  friend class pqxx::internal::gate::transaction_tablereader;
424  void PQXX_PRIVATE BeginCopyRead(const PGSTD::string &, const PGSTD::string &);
425  bool ReadCopyLine(PGSTD::string &);
426 
427  friend class pqxx::internal::gate::transaction_tablewriter;
428  void PQXX_PRIVATE BeginCopyWrite(
429  const PGSTD::string &Table,
430  const PGSTD::string &Columns);
431  void WriteCopyLine(const PGSTD::string &);
432  void EndCopyWrite();
433 
434  friend class pqxx::internal::gate::transaction_subtransaction;
435 
436  connection_base &m_Conn;
437 
438  internal::unique<internal::transactionfocus> m_Focus;
439  Status m_Status;
440  bool m_Registered;
441  PGSTD::map<PGSTD::string, PGSTD::string> m_Vars;
442  PGSTD::string m_PendingError;
443 
449  transaction_base &operator=(const transaction_base &);
450 };
451 
452 } // namespace pqxx
453 
454 
455 #include "pqxx/compiler-internal-post.hxx"
456 
457 #endif
458