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
00034
00035
00036 namespace pqxx
00037 {
00038 class in_doubt_error;
00039 class Result;
00040 class TransactionItf;
00041 class Trigger;
00042
00043 extern "C" { typedef void (*NoticeProcessor)(void *arg, const char *msg); }
00044
00045
00047 template<> inline PGSTD::string Classname(const TransactionItf *)
00048 {
00049 return "TransactionItf";
00050 }
00051
00052
00054
00055 class broken_connection : public PGSTD::runtime_error
00056 {
00057 public:
00058 broken_connection() : PGSTD::runtime_error("Connection to back end failed") {}
00059 explicit broken_connection(const PGSTD::string &whatarg) :
00060 PGSTD::runtime_error(whatarg) {}
00061 };
00062
00063
00065
00073 class PQXX_LIBEXPORT Connection
00074 {
00075 public:
00077
00086 explicit Connection(const PGSTD::string &ConnInfo,
00087 bool Immediate=true);
00088
00090 ~Connection();
00091
00093 void Disconnect() const throw ();
00094
00096 bool is_open() const;
00097
00099 bool IsOpen() const { return is_open(); }
00100
00102 template<typename TRANSACTOR>
00103 void Perform(const TRANSACTOR &, int Attempts=3);
00104
00106
00110 NoticeProcessor SetNoticeProcessor(NoticeProcessor, void *arg);
00111
00113 void ProcessNotice(const char[]) throw ();
00115
00116 { ProcessNotice(msg.c_str()); }
00117
00119 void Trace(FILE *);
00121
00122
00123
00125 void GetNotifs();
00126
00127
00128
00130 const char *DbName() const throw ()
00131 { Activate(); return PQdb(m_Conn); }
00132
00134 const char *UserName() const throw ()
00135 { Activate(); return PQuser(m_Conn); }
00136
00138 const char *HostName() const throw ()
00139 { Activate(); return PQhost(m_Conn); }
00140
00142 const char *Port() const throw ()
00143 { Activate(); return PQport(m_Conn); }
00144
00146 const char *Options() const throw ()
00147 { return m_ConnInfo.c_str(); }
00148
00150
00157 int BackendPID() const
00158 { return m_Conn ? PQbackendPID(m_Conn) : 0; }
00159
00161
00171 void Activate() const { if (!m_Conn) Connect(); }
00172
00174
00182 void Deactivate() const;
00183
00184 private:
00185 void Connect() const;
00186 void SetupState() const;
00187 void InternalSetTrace() const;
00188 int Status() const { return PQstatus(m_Conn); }
00189 const char *ErrMsg() const;
00190 void Reset(const char OnReconnect[]=0);
00191
00192 PGSTD::string m_ConnInfo;
00193 mutable PGconn *m_Conn;
00194 Unique<TransactionItf> m_Trans;
00195
00197 mutable NoticeProcessor m_NoticeProcessor;
00198 void *m_NoticeProcessorArg;
00199 FILE *m_Trace;
00200
00201 typedef PGSTD::multimap<PGSTD::string, pqxx::Trigger *> TriggerList;
00202 TriggerList m_Triggers;
00203
00204 friend class TransactionItf;
00205 Result Exec(const char[], int Retries=3, const char OnReconnect[]=0);
00206 void RegisterTransaction(const TransactionItf *);
00207 void UnregisterTransaction(const TransactionItf *) throw ();
00208 void MakeEmpty(Result &, ExecStatusType=PGRES_EMPTY_QUERY);
00209 void BeginCopyRead(const PGSTD::string &Table);
00210 bool ReadCopyLine(PGSTD::string &);
00211 void BeginCopyWrite(const PGSTD::string &Table);
00212 void WriteCopyLine(const PGSTD::string &);
00213 void EndCopy();
00214
00215 friend class Trigger;
00216 void AddTrigger(Trigger *);
00217 void RemoveTrigger(Trigger *) throw ();
00218
00219
00220 Connection(const Connection &);
00221 Connection &operator=(const Connection &);
00222 };
00223
00224
00225
00236 template<typename TRANSACTOR>
00237 inline void Connection::Perform(const TRANSACTOR &T,
00238 int Attempts)
00239 {
00240 if (Attempts <= 0) return;
00241
00242 bool Done = false;
00243
00244
00245
00246 do
00247 {
00248 --Attempts;
00249
00250
00251 TRANSACTOR T2(T);
00252 try
00253 {
00254 typename TRANSACTOR::argument_type X(*this, T2.Name());
00255 T2(X);
00256 X.Commit();
00257 Done = true;
00258 }
00259 catch (const in_doubt_error &)
00260 {
00261
00262
00263 T2.OnDoubt();
00264 throw;
00265 }
00266 catch (const PGSTD::exception &e)
00267 {
00268
00269 T2.OnAbort(e.what());
00270 if (Attempts <= 0) throw;
00271 continue;
00272 }
00273 catch (...)
00274 {
00275
00276 T2.OnAbort("Unknown exception");
00277 throw;
00278 }
00279
00280 T2.OnCommit();
00281 } while (!Done);
00282 }
00283
00284
00285 }
00286
00287 #endif
00288