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 <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
00036 extern "C" void pqxxNoticeCaller(void *, const char *);
00037
00038 namespace pqxx
00039 {
00040 class in_doubt_error;
00041 class Result;
00042 class TransactionItf;
00043 class Trigger;
00044
00046 extern "C" { typedef void (*NoticeProcessor)(void *arg, const char *msg); }
00047
00049
00053 struct Noticer
00054 {
00055 virtual ~Noticer() {}
00056 virtual void operator()(const char Msg[]) throw () =0;
00057 };
00058
00059
00061 template<> inline PGSTD::string Classname(const TransactionItf *)
00062 {
00063 return "TransactionItf";
00064 }
00065
00066
00068
00069 class broken_connection : public PGSTD::runtime_error
00070 {
00071 public:
00072 broken_connection() : PGSTD::runtime_error("Connection to back end failed") {}
00073 explicit broken_connection(const PGSTD::string &whatarg) :
00074 PGSTD::runtime_error(whatarg) {}
00075 };
00076
00077
00079
00087 class PQXX_LIBEXPORT Connection
00088 {
00089 public:
00091
00100 explicit Connection(const PGSTD::string &ConnInfo,
00101 bool Immediate=true);
00102
00104
00114 explicit Connection(const char ConnInfo[], bool Immediate=true);
00115
00117 ~Connection();
00118
00120 void Disconnect() const throw ();
00121
00123 bool is_open() const;
00124
00126 bool IsOpen() const { return is_open(); }
00127
00129
00137 template<typename TRANSACTOR>
00138 void Perform(const TRANSACTOR &T, int Attempts=3);
00139
00141
00144 NoticeProcessor SetNoticeProcessor(NoticeProcessor, void *arg);
00145
00147
00150 std::auto_ptr<Noticer> SetNoticer(std::auto_ptr<Noticer> N);
00151 Noticer *GetNoticer() const throw () { return m_Noticer.get(); }
00152
00154 void ProcessNotice(const char[]) throw ();
00156
00157 { ProcessNotice(msg.c_str()); }
00158
00160 void Trace(FILE *);
00162
00163
00164
00166 void GetNotifs();
00167
00168
00169
00171 const char *DbName() const throw ()
00172 { Activate(); return PQdb(m_Conn); }
00173
00175 const char *UserName() const throw ()
00176 { Activate(); return PQuser(m_Conn); }
00177
00179 const char *HostName() const throw ()
00180 { Activate(); return PQhost(m_Conn); }
00181
00183 const char *Port() const throw ()
00184 { Activate(); return PQport(m_Conn); }
00185
00187 const char *Options() const throw ()
00188 { return m_ConnInfo.c_str(); }
00189
00191
00198 int BackendPID() const
00199 { return m_Conn ? PQbackendPID(m_Conn) : 0; }
00200
00202
00212 void Activate() const { if (!m_Conn) Connect(); }
00213
00215
00223 void Deactivate() const;
00224
00225 private:
00226 void Connect() const;
00227 void SetupState() const;
00228 void InternalSetTrace() const;
00229 int Status() const { return PQstatus(m_Conn); }
00230 const char *ErrMsg() const;
00231 void Reset(const char OnReconnect[]=0);
00232
00233 PGSTD::string m_ConnInfo;
00234 mutable PGconn *m_Conn;
00235 Unique<TransactionItf> m_Trans;
00236
00238 mutable NoticeProcessor m_NoticeProcessor;
00239 void *m_NoticeProcessorArg;
00240 std::auto_ptr<Noticer> m_Noticer;
00241 FILE *m_Trace;
00242
00243 typedef PGSTD::multimap<PGSTD::string, pqxx::Trigger *> TriggerList;
00244 TriggerList m_Triggers;
00245
00246 friend class TransactionItf;
00247 Result Exec(const char[], int Retries=3, const char OnReconnect[]=0);
00248 void RegisterTransaction(const TransactionItf *);
00249 void UnregisterTransaction(const TransactionItf *) throw ();
00250 void MakeEmpty(Result &, ExecStatusType=PGRES_EMPTY_QUERY);
00251 void BeginCopyRead(const PGSTD::string &Table);
00252 bool ReadCopyLine(PGSTD::string &);
00253 void BeginCopyWrite(const PGSTD::string &Table);
00254 void WriteCopyLine(const PGSTD::string &);
00255 void EndCopy();
00256
00257 friend class Trigger;
00258 void AddTrigger(Trigger *);
00259 void RemoveTrigger(Trigger *) throw ();
00260
00261
00262 Connection(const Connection &);
00263 Connection &operator=(const Connection &);
00264 };
00265
00266
00267
00278 template<typename TRANSACTOR>
00279 inline void Connection::Perform(const TRANSACTOR &T,
00280 int Attempts)
00281 {
00282 if (Attempts <= 0) return;
00283
00284 bool Done = false;
00285
00286
00287
00288 do
00289 {
00290 --Attempts;
00291
00292
00293 TRANSACTOR T2(T);
00294 try
00295 {
00296 typename TRANSACTOR::argument_type X(*this, T2.Name());
00297 T2(X);
00298 X.Commit();
00299 Done = true;
00300 }
00301 catch (const in_doubt_error &)
00302 {
00303
00304
00305 T2.OnDoubt();
00306 throw;
00307 }
00308 catch (const PGSTD::exception &e)
00309 {
00310
00311 T2.OnAbort(e.what());
00312 if (Attempts <= 0) throw;
00313 continue;
00314 }
00315 catch (...)
00316 {
00317
00318 T2.OnAbort("Unknown exception");
00319 throw;
00320 }
00321
00322 T2.OnCommit();
00323 } while (!Done);
00324 }
00325
00326
00327 }
00328
00329 #endif
00330