00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 #ifndef PQXX_CONNECTIONITF_H
00015 #define PQXX_CONNECTIONITF_H
00016 
00017 #include <map>
00018 #include <memory>
00019 #include <stdexcept>
00020 
00021 #include "pqxx/transactor.h"
00022 #include "pqxx/util.h"
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 namespace pqxx
00035 {
00036 class in_doubt_error;   
00037 class Result;
00038 class TransactionItf;
00039 class Trigger;
00040 
00042 
00046 struct PQXX_LIBEXPORT Noticer
00047 {
00048   virtual ~Noticer() {}
00049   virtual void operator()(const char Msg[]) throw () =0;
00050 };
00051 
00052 
00054 template<> inline PGSTD::string Classname(const TransactionItf *) 
00055 { 
00056   return "TransactionItf"; 
00057 }
00058 
00059 
00061 
00062 class PQXX_LIBEXPORT broken_connection : public PGSTD::runtime_error
00063 {
00064 public:
00065   broken_connection() : PGSTD::runtime_error("Connection to back end failed") {}
00066   explicit broken_connection(const PGSTD::string &whatarg) : 
00067     PGSTD::runtime_error(whatarg) {}
00068 };
00069 
00070 
00072 
00081 class PQXX_LIBEXPORT ConnectionItf
00082 {
00083 public:
00085 
00088   explicit ConnectionItf(const PGSTD::string &ConnInfo);                
00089 
00091 
00095   explicit ConnectionItf(const char ConnInfo[]);                        
00096 
00098   virtual ~ConnectionItf() =0;                                          
00099 
00101   void Disconnect() const throw ();                                     
00102 
00104   bool is_open() const;                                                 
00105 
00107 
00115   template<typename TRANSACTOR> 
00116   void Perform(const TRANSACTOR &T, int Attempts=3);                    
00117 
00119 
00122   std::auto_ptr<Noticer> SetNoticer(std::auto_ptr<Noticer> N);          
00123   Noticer *GetNoticer() const throw () { return m_Noticer.get(); }      
00124 
00126   void ProcessNotice(const char[]) throw ();                            
00128 
00129         { ProcessNotice(msg.c_str()); }
00130 
00132   void Trace(FILE *);                                                   
00133 
00135   void GetNotifs();                                                     
00136 
00137   
00138  
00140   const char *DbName() const throw ()                                   
00141         { Activate(); return PQdb(m_Conn); }
00142 
00144   const char *UserName() const throw ()                                 
00145         { Activate(); return  PQuser(m_Conn); }
00146 
00148   const char *HostName() const throw ()                                 
00149         { Activate(); return PQhost(m_Conn); }
00150 
00152   const char *Port() const throw ()                                     
00153         { Activate(); return PQport(m_Conn); }
00154 
00156   const char *Options() const throw ()                                  
00157         { return m_ConnInfo.c_str(); }
00158 
00160 
00167   int BackendPID() const                                                
00168         { return m_Conn ? PQbackendPID(m_Conn) : 0; }
00169 
00171 
00181   void Activate() const { if (!m_Conn) Connect(); }                     
00182 
00184 
00192   void Deactivate() const;                                              
00193 
00194 protected:
00196   void Connect() const;
00197 
00198 private:
00199   void SetupState() const;
00200   void InternalSetTrace() const;
00201   int Status() const { return PQstatus(m_Conn); }
00202   const char *ErrMsg() const;
00203   void Reset(const char OnReconnect[]=0);
00204 
00205   PGSTD::string m_ConnInfo;     
00206   mutable PGconn *m_Conn;       
00207   Unique<TransactionItf> m_Trans;
00208 
00209   std::auto_ptr<Noticer> m_Noticer;     
00210   FILE *m_Trace;                
00211 
00212   typedef PGSTD::multimap<PGSTD::string, pqxx::Trigger *> TriggerList;
00213   TriggerList m_Triggers;       
00214 
00215   friend class TransactionItf;
00216   Result Exec(const char[], int Retries=3, const char OnReconnect[]=0);
00217   void RegisterTransaction(const TransactionItf *);
00218   void UnregisterTransaction(const TransactionItf *) throw ();
00219   void MakeEmpty(Result &, ExecStatusType=PGRES_EMPTY_QUERY);
00220   void BeginCopyRead(const PGSTD::string &Table);
00221   bool ReadCopyLine(PGSTD::string &);
00222   void BeginCopyWrite(const PGSTD::string &Table);
00223   void WriteCopyLine(const PGSTD::string &);
00224   void EndCopy();
00225 
00226   friend class LargeObject;
00227   PGconn *RawConnection() const { return m_Conn; }
00228 
00229   friend class Trigger;
00230   void AddTrigger(Trigger *);
00231   void RemoveTrigger(Trigger *) throw ();
00232 
00233   
00234   ConnectionItf(const ConnectionItf &);
00235   ConnectionItf &operator=(const ConnectionItf &);
00236 };
00237 
00238 
00239 }
00240 
00241 
00252 template<typename TRANSACTOR> 
00253 inline void pqxx::ConnectionItf::Perform(const TRANSACTOR &T,
00254                                          int Attempts)
00255 {
00256   if (Attempts <= 0) return;
00257 
00258   bool Done = false;
00259 
00260   
00261   
00262   do
00263   {
00264     --Attempts;
00265 
00266     
00267     TRANSACTOR T2(T);
00268     try
00269     {
00270       typename TRANSACTOR::argument_type X(*this, T2.Name());
00271       T2(X);
00272       X.Commit();
00273       Done = true;
00274     }
00275     catch (const in_doubt_error &)
00276     {
00277       
00278       
00279       T2.OnDoubt();
00280       throw;
00281     }
00282     catch (const PGSTD::exception &e)
00283     {
00284       
00285       T2.OnAbort(e.what());
00286       if (Attempts <= 0) throw;
00287       continue;
00288     }
00289     catch (...)
00290     {
00291       
00292       T2.OnAbort("Unknown exception");
00293       throw;
00294     }
00295 
00296     T2.OnCommit();
00297   } while (!Done);
00298 }
00299 
00300 
00301 #endif
00302