libpqxx 4.0
|
00001 /*------------------------------------------------------------------------- 00002 * 00003 * FILE 00004 * pqxx/transaction_base.hxx 00005 * 00006 * DESCRIPTION 00007 * common code and definitions for the transaction classes. 00008 * pqxx::transaction_base defines the interface for any abstract class that 00009 * represents a database transaction 00010 * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/transaction_base instead. 00011 * 00012 * Copyright (c) 2001-2011, Jeroen T. Vermeulen <jtv@xs4all.nl> 00013 * 00014 * See COPYING for copyright license. If you did not receive a file called 00015 * COPYING with this source code, please notify the distributor of this mistake, 00016 * or contact the author. 00017 * 00018 *------------------------------------------------------------------------- 00019 */ 00020 #ifndef PQXX_H_TRANSACTION_BASE 00021 #define PQXX_H_TRANSACTION_BASE 00022 00023 #include "pqxx/compiler-public.hxx" 00024 #include "pqxx/compiler-internal-pre.hxx" 00025 00026 /* End-user programs need not include this file, unless they define their own 00027 * transaction classes. This is not something the typical program should want 00028 * to do. 00029 * 00030 * However, reading this file is worthwhile because it defines the public 00031 * interface for the available transaction classes such as transaction and 00032 * nontransaction. 00033 */ 00034 00035 #include "pqxx/connection_base" 00036 #include "pqxx/isolation" 00037 #include "pqxx/result" 00038 00039 /* Methods tested in eg. self-test program test001 are marked with "//[t1]" 00040 */ 00041 00042 namespace pqxx 00043 { 00044 class connection_base; 00045 class transaction_base; 00046 00047 00048 namespace internal 00049 { 00050 class sql_cursor; 00051 00052 class PQXX_LIBEXPORT transactionfocus : public virtual namedclass 00053 { 00054 public: 00055 explicit transactionfocus(transaction_base &t) : 00056 namedclass("transactionfocus"), 00057 m_Trans(t), 00058 m_registered(false) 00059 { 00060 } 00061 00062 protected: 00063 void register_me(); 00064 void unregister_me() throw (); 00065 void reg_pending_error(const PGSTD::string &) throw (); 00066 bool registered() const throw () { return m_registered; } 00067 00068 transaction_base &m_Trans; 00069 00070 private: 00071 bool m_registered; 00072 00074 transactionfocus(); 00076 transactionfocus(const transactionfocus &); 00078 transactionfocus &operator=(const transactionfocus &); 00079 }; 00080 00081 00082 class PQXX_LIBEXPORT parameterized_invocation : statement_parameters 00083 { 00084 public: 00085 parameterized_invocation(connection_base &, const PGSTD::string &query); 00086 00087 parameterized_invocation &operator()() { add_param(); return *this; } 00088 parameterized_invocation &operator()(const binarystring &v) 00089 { add_binary_param(v, true); return *this; } 00090 template<typename T> parameterized_invocation &operator()(const T &v) 00091 { add_param(v, true); return *this; } 00092 parameterized_invocation &operator()(const binarystring &v, bool nonnull) 00093 { add_binary_param(v, nonnull); return *this; } 00094 template<typename T> 00095 parameterized_invocation &operator()(const T &v, bool nonnull) 00096 { add_param(v, nonnull); return *this; } 00097 00098 result exec(); 00099 00100 private: 00102 parameterized_invocation &operator=(const parameterized_invocation &); 00103 00104 connection_base &m_home; 00105 const PGSTD::string m_query; 00106 }; 00107 } // namespace internal 00108 00109 00110 namespace internal 00111 { 00112 namespace gate 00113 { 00114 class transaction_subtransaction; 00115 class transaction_tablereader; 00116 class transaction_tablewriter; 00117 class transaction_transactionfocus; 00118 } // namespace internal::gate 00119 } // namespace internal 00120 00121 00123 00133 class PQXX_LIBEXPORT PQXX_NOVTABLE transaction_base : 00134 public virtual internal::namedclass 00135 { 00136 public: 00138 typedef isolation_traits<read_committed> isolation_tag; 00139 00140 virtual ~transaction_base() =0; //[t1] 00141 00143 00155 void commit(); //[t1] 00156 00158 00161 void abort(); //[t10] 00162 00167 00168 PGSTD::string esc(const char str[]) const { return conn().esc(str); } 00170 PGSTD::string esc(const char str[], size_t maxlen) const 00171 { return conn().esc(str, maxlen); } 00173 PGSTD::string esc(const PGSTD::string &str) const { return conn().esc(str); } 00174 00176 00187 PGSTD::string esc_raw(const unsigned char str[], size_t len) const //[t62] 00188 { return conn().esc_raw(str, len); } 00190 PGSTD::string esc_raw(const PGSTD::string &) const; //[t62] 00191 00193 00194 template<typename T> PGSTD::string quote(const T &t) const 00195 { return conn().quote(t); } 00196 00198 PGSTD::string quote_raw(const unsigned char str[], size_t len) const 00199 { return conn().quote_raw(str, len); } 00200 00201 PGSTD::string quote_raw(const PGSTD::string &str) const; 00202 00204 PGSTD::string quote_name(const PGSTD::string &identifier) const 00205 { return conn().quote_name(identifier); } 00207 00209 00224 result exec(const PGSTD::string &Query, 00225 const PGSTD::string &Desc=PGSTD::string()); //[t1] 00226 00227 result exec(const PGSTD::stringstream &Query, 00228 const PGSTD::string &Desc=PGSTD::string()) 00229 { return exec(Query.str(), Desc); } 00230 00232 /* Use this to build up a parameterized statement invocation, then invoke it 00233 * using @c exec() 00234 * 00235 * Example: @c trans.parameterized("SELECT $1 + 1")(1).exec(); 00236 */ 00237 internal::parameterized_invocation parameterized(const PGSTD::string &query); 00238 00243 00244 00288 prepare::invocation prepared(const PGSTD::string &statement=PGSTD::string()); 00289 00291 00296 00297 void process_notice(const char Msg[]) const //[t14] 00298 { m_Conn.process_notice(Msg); } 00300 void process_notice(const PGSTD::string &Msg) const //[t14] 00301 { m_Conn.process_notice(Msg); } 00303 00305 connection_base &conn() const { return m_Conn; } //[t4] 00306 00308 00316 void set_variable(const PGSTD::string &Var, const PGSTD::string &Val);//[t61] 00317 00319 00328 PGSTD::string get_variable(const PGSTD::string &); //[t61] 00329 00330 00331 protected: 00333 00339 explicit transaction_base(connection_base &c, bool direct=true); 00340 00342 00344 void Begin(); 00345 00347 void End() throw (); 00348 00350 virtual void do_begin() =0; 00352 virtual result do_exec(const char Query[]) =0; 00354 virtual void do_commit() =0; 00356 virtual void do_abort() =0; 00357 00358 // For use by implementing class: 00359 00361 00369 result DirectExec(const char C[], int Retries=0); 00370 00372 void reactivation_avoidance_clear() throw () 00373 {m_reactivation_avoidance.clear();} 00374 00375 protected: 00377 00379 internal::reactivation_avoidance_counter m_reactivation_avoidance; 00380 00381 private: 00382 /* A transaction goes through the following stages in its lifecycle: 00383 * <ul> 00384 * <li> nascent: the transaction hasn't actually begun yet. If our connection 00385 * fails at this stage, it may recover and the transaction can attempt to 00386 * establish itself again. 00387 * <li> active: the transaction has begun. Since no commit command has been 00388 * issued, abortion is implicit if the connection fails now. 00389 * <li> aborted: an abort has been issued; the transaction is terminated and 00390 * its changes to the database rolled back. It will accept no further 00391 * commands. 00392 * <li> committed: the transaction has completed successfully, meaning that a 00393 * commit has been issued. No further commands are accepted. 00394 * <li> in_doubt: the connection was lost at the exact wrong time, and there 00395 * is no way of telling whether the transaction was committed or aborted. 00396 * </ul> 00397 * 00398 * Checking and maintaining state machine logic is the responsibility of the 00399 * base class (ie., this one). 00400 */ 00401 enum Status 00402 { 00403 st_nascent, 00404 st_active, 00405 st_aborted, 00406 st_committed, 00407 st_in_doubt 00408 }; 00409 00411 void PQXX_PRIVATE activate(); 00412 00413 void PQXX_PRIVATE CheckPendingError(); 00414 00415 template<typename T> bool parm_is_null(T *p) const throw () { return !p; } 00416 template<typename T> bool parm_is_null(T) const throw () { return false; } 00417 00418 friend class pqxx::internal::gate::transaction_transactionfocus; 00419 void PQXX_PRIVATE RegisterFocus(internal::transactionfocus *); 00420 void PQXX_PRIVATE UnregisterFocus(internal::transactionfocus *) throw (); 00421 void PQXX_PRIVATE RegisterPendingError(const PGSTD::string &) throw (); 00422 00423 friend class pqxx::internal::gate::transaction_tablereader; 00424 void PQXX_PRIVATE BeginCopyRead(const PGSTD::string &, const PGSTD::string &); 00425 bool ReadCopyLine(PGSTD::string &); 00426 00427 friend class pqxx::internal::gate::transaction_tablewriter; 00428 void PQXX_PRIVATE BeginCopyWrite( 00429 const PGSTD::string &Table, 00430 const PGSTD::string &Columns); 00431 void WriteCopyLine(const PGSTD::string &); 00432 void EndCopyWrite(); 00433 00434 friend class pqxx::internal::gate::transaction_subtransaction; 00435 00436 connection_base &m_Conn; 00437 00438 internal::unique<internal::transactionfocus> m_Focus; 00439 Status m_Status; 00440 bool m_Registered; 00441 PGSTD::map<PGSTD::string, PGSTD::string> m_Vars; 00442 PGSTD::string m_PendingError; 00443 00445 transaction_base(); 00447 transaction_base(const transaction_base &); 00449 transaction_base &operator=(const transaction_base &); 00450 }; 00451 00452 } // namespace pqxx 00453 00454 00455 #include "pqxx/compiler-internal-post.hxx" 00456 00457 #endif 00458