1 // This may look like C code, but it's really -*- C++ -*-
2 /*
3  * Copyright (C) 2008 Emweb bv, Herent, Belgium.
4  *
5  * See the LICENSE file for terms of use.
6  *
7  * Contributed by: Hilary Cheng
8  */
9 #ifndef WT_DBO_BACKEND_POSTGRES_H_
10 #define WT_DBO_BACKEND_POSTGRES_H_
11 
12 #include <Wt/Dbo/SqlConnection.h>
13 #include <Wt/Dbo/SqlStatement.h>
14 #include <Wt/Dbo/backend/WDboPostgresDllDefs.h>
15 
16 #include <chrono>
17 
18 struct pg_conn;
19 typedef struct pg_conn PGconn;
20 
21 namespace Wt {
22   namespace Dbo {
23     namespace backend {
24 
25 /*! \class Postgres Wt/Dbo/backend/Postgres.h Wt/Dbo/backend/Postgres.h
26  *  \brief A PostgreSQL connection
27  *
28  * This class provides the backend implementation for PostgreSQL databases.
29  *
30  * When applicable, exceptions from the backend will return the
31  * five-character SQLSTATE error codes, as in
32  * http://www.postgresql.org/docs/8.1/static/errcodes-appendix.html, in
33  * Exception::code().
34  *
35  * \ingroup dbo
36  */
37 class WTDBOPOSTGRES_API Postgres : public SqlConnection
38 {
39 public:
40   /*! \brief Creates new PostgreSQL backend connection.
41    *
42    * The connection is not yet open, and requires a connect() before it
43    * can be used.
44    */
45   Postgres();
46 
47   /*! \brief Opens a new PostgreSQL backend connection.
48    *
49    * The \p db may be any of the values supported by PQconnectdb().
50    */
51   Postgres(const std::string& db);
52 
53   /*! \brief Copies a PostgreSQL connection.
54    *
55    * This creates a new connection with the same settings as another
56    * connection.
57    *
58    * \sa clone()
59    */
60   Postgres(const Postgres& other);
61 
62   /*! \brief Destructor.
63    *
64    * Closes the connection.
65    */
66   ~Postgres();
67 
68   virtual std::unique_ptr<SqlConnection> clone() const override;
69 
70   /*! \brief Tries to connect.
71    *
72    * Throws an exception if there was a problem, otherwise true.
73    * An example connecion string could be:
74    * "host=127.0.0.1 user=test password=test port=5432 dbname=test"
75    */
76   bool connect(const std::string& db);
77 
78   /*! \brief Disconnects.
79    *
80    * This disconnects from the server. Any subsequent action on the connection
81    * will result in an automatic reconnect.
82    *
83    * \sa reconnect()
84    */
85   void disconnect();
86 
87   /*! \brief Reconnect.
88    *
89    * This will try to reconnect a previously disconnected connection. If the connection
90    * is still open, it will first disconnect.
91    */
92   bool reconnect();
93 
94   /*! \brief Returns the underlying connection.
95    */
connection()96   PGconn *connection() { return conn_; }
97 
98   /*! \brief Sets a timeout.
99    *
100    * Sets a timeout for queries. When the query exceeds this timeout, the connection
101    * is closed using disconnect() and an exception is thrown.
102    *
103    * In practice, as a result, the connection (and statements) can still be used again
104    * when a successful reconnect() is performed.
105    *
106    * A value of 0 disables the timeout handling, allowing operations
107    * to take as much time is they require.
108    *
109    * The default value is 0.
110    */
111   void setTimeout(std::chrono::microseconds timeout);
112 
113   /*! \brief Returns the timeout.
114    *
115    * \sa setTimeout()
116    */
timeout()117   std::chrono::microseconds timeout() const { return timeout_; }
118 
119   /*! \brief Sets the maximum lifetime for the underlying connection.
120    *
121    * The maximum lifetime is specified in seconds. If set to a value >
122    * 0, then the underlying connection object will be closed and
123    * reopened when the connection has been open longer than this
124    * lifetime.
125    *
126    * The default value is -1 (unlimited lifetime).
127    */
128   void setMaximumLifetime(std::chrono::seconds seconds);
129 
130   virtual void executeSql(const std::string &sql) override;
131 
132   virtual void startTransaction() override;
133   virtual void commitTransaction() override;
134   virtual void rollbackTransaction() override;
135 
136   virtual std::unique_ptr<SqlStatement> prepareStatement(const std::string& sql) override;
137 
138   /** @name Methods that return dialect information
139    */
140   //!@{
141   virtual std::string autoincrementSql() const override;
142   virtual std::vector<std::string>
143     autoincrementCreateSequenceSql(const std::string &table,
144                                    const std::string &id) const override;
145   virtual std::vector<std::string>
146     autoincrementDropSequenceSql(const std::string &table,
147                                  const std::string &id) const override;
148   virtual std::string autoincrementType() const override;
149   virtual std::string autoincrementInsertSuffix(const std::string& id) const override;
150   virtual const char *dateTimeType(SqlDateTimeType type) const override;
151   virtual const char *blobType() const override;
152   virtual bool supportAlterTable() const override;
153   virtual bool supportDeferrableFKConstraint() const override;
154   virtual bool requireSubqueryAlias() const override;
155   //!@}
156 
157   void checkConnection(std::chrono::seconds margin);
158 
159 private:
160   std::string connInfo_;
161   PGconn *conn_;
162   std::chrono::microseconds timeout_;
163   std::chrono::seconds maximumLifetime_;
164   std::chrono::steady_clock::time_point connectTime_;
165 
166   void exec(const std::string& sql, bool showQuery);
167 };
168 
169     }
170   }
171 }
172 
173 #endif // WT_DBO_BACKEND_POSTGRES_H_
174