00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #ifndef PQXX_CONNECTION_H
00015 #define PQXX_CONNECTION_H
00016
00017 #include <map>
00018 #include <stdexcept>
00019
00020 #include "pqxx/transactor.h"
00021 #include "pqxx/util.h"
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00035 extern "C" void pqxxNoticeCaller(void *, const char *);
00036
00037 namespace pqxx
00038 {
00039 class in_doubt_error;
00040 class Result;
00041 class TransactionItf;
00042 class Trigger;
00043
00045 extern "C" { typedef void (*NoticeProcessor)(void *arg, const char *msg); }
00046
00048 struct Noticer
00049 {
00050 virtual ~Noticer() {}
00051 virtual void operator()(const char Msg[]) throw () =0;
00052 };
00053
00054
00056 template<> inline PGSTD::string Classname(const TransactionItf *)
00057 {
00058 return "TransactionItf";
00059 }
00060
00061
00063
00064 class broken_connection : public PGSTD::runtime_error
00065 {
00066 public:
00067 broken_connection() : PGSTD::runtime_error("Connection to back end failed") {}
00068 explicit broken_connection(const PGSTD::string &whatarg) :
00069 PGSTD::runtime_error(whatarg) {}
00070 };
00071
00072
00074
00082 class PQXX_LIBEXPORT Connection
00083 {
00084 public:
00086
00095 explicit Connection(const PGSTD::string &ConnInfo,
00096 bool Immediate=true);
00097
00099
00109 explicit Connection(const char ConnInfo[], bool Immediate=true);
00110
00112
00116 Connection();
00117
00119 ~Connection();
00120
00122 void Disconnect() const throw ();
00123
00125 bool is_open() const;
00126
00128 bool IsOpen() const { return is_open(); }
00129
00131 template<typename TRANSACTOR>
00132 void Perform(const TRANSACTOR &, int Attempts=3);
00133
00135
00138 NoticeProcessor SetNoticeProcessor(NoticeProcessor, void *arg);
00139
00141
00143 std::auto_ptr<Noticer> SetNoticer(std::auto_ptr<Noticer>);
00144 Noticer *GetNoticer() const throw () { return m_Noticer.get(); }
00145
00147 void ProcessNotice(const char[]) throw ();
00149
00150 { ProcessNotice(msg.c_str()); }
00151
00153 void Trace(FILE *);
00155
00156
00157
00159 void GetNotifs();
00160
00161
00162
00164 const char *DbName() const throw ()
00165 { Activate(); return PQdb(m_Conn); }
00166
00168 const char *UserName() const throw ()
00169 { Activate(); return PQuser(m_Conn); }
00170
00172 const char *HostName() const throw ()
00173 { Activate(); return PQhost(m_Conn); }
00174
00176 const char *Port() const throw ()
00177 { Activate(); return PQport(m_Conn); }
00178
00180 const char *Options() const throw ()
00181 { return m_ConnInfo.c_str(); }
00182
00184
00191 int BackendPID() const
00192 { return m_Conn ? PQbackendPID(m_Conn) : 0; }
00193
00195
00205 void Activate() const { if (!m_Conn) Connect(); }
00206
00208
00216 void Deactivate() const;
00217
00218 private:
00219 void Connect() const;
00220 void SetupState() const;
00221 void InternalSetTrace() const;
00222 int Status() const { return PQstatus(m_Conn); }
00223 const char *ErrMsg() const;
00224 void Reset(const char OnReconnect[]=0);
00225
00226 PGSTD::string m_ConnInfo;
00227 mutable PGconn *m_Conn;
00228 Unique<TransactionItf> m_Trans;
00229
00231 mutable NoticeProcessor m_NoticeProcessor;
00232 void *m_NoticeProcessorArg;
00233 std::auto_ptr<Noticer> m_Noticer;
00234 FILE *m_Trace;
00235
00236 typedef PGSTD::multimap<PGSTD::string, pqxx::Trigger *> TriggerList;
00237 TriggerList m_Triggers;
00238
00239 friend class TransactionItf;
00240 Result Exec(const char[], int Retries=3, const char OnReconnect[]=0);
00241 void RegisterTransaction(const TransactionItf *);
00242 void UnregisterTransaction(const TransactionItf *) throw ();
00243 void MakeEmpty(Result &, ExecStatusType=PGRES_EMPTY_QUERY);
00244 void BeginCopyRead(const PGSTD::string &Table);
00245 bool ReadCopyLine(PGSTD::string &);
00246 void BeginCopyWrite(const PGSTD::string &Table);
00247 void WriteCopyLine(const PGSTD::string &);
00248 void EndCopy();
00249
00250 friend class Trigger;
00251 void AddTrigger(Trigger *);
00252 void RemoveTrigger(Trigger *) throw ();
00253
00254
00255 Connection(const Connection &);
00256 Connection &operator=(const Connection &);
00257 };
00258
00259
00260
00271 template<typename TRANSACTOR>
00272 inline void Connection::Perform(const TRANSACTOR &T,
00273 int Attempts)
00274 {
00275 if (Attempts <= 0) return;
00276
00277 bool Done = false;
00278
00279
00280
00281 do
00282 {
00283 --Attempts;
00284
00285
00286 TRANSACTOR T2(T);
00287 try
00288 {
00289 typename TRANSACTOR::argument_type X(*this, T2.Name());
00290 T2(X);
00291 X.Commit();
00292 Done = true;
00293 }
00294 catch (const in_doubt_error &)
00295 {
00296
00297
00298 T2.OnDoubt();
00299 throw;
00300 }
00301 catch (const PGSTD::exception &e)
00302 {
00303
00304 T2.OnAbort(e.what());
00305 if (Attempts <= 0) throw;
00306 continue;
00307 }
00308 catch (...)
00309 {
00310
00311 T2.OnAbort("Unknown exception");
00312 throw;
00313 }
00314
00315 T2.OnCommit();
00316 } while (!Done);
00317 }
00318
00319
00320 }
00321
00322 #endif
00323