]> git.stg.codes - stg.git/blob - projects/stargazer/plugins/store/postgresql/postgresql_store.cpp
35551c5db1ecf24bd509fe06ad3c4cd1a78e4a1c
[stg.git] / projects / stargazer / plugins / store / postgresql / postgresql_store.cpp
1 /*
2  *    This program is free software; you can redistribute it and/or modify
3  *    it under the terms of the GNU General Public License as published by
4  *    the Free Software Foundation; either version 2 of the License, or
5  *    (at your option) any later version.
6  *
7  *    This program is distributed in the hope that it will be useful,
8  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
9  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  *    GNU General Public License for more details.
11  *
12  *    You should have received a copy of the GNU General Public License
13  *    along with this program; if not, write to the Free Software
14  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
15  */
16
17 /*
18  *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
19  */
20
21 /*
22  *  This file contains a realization of a base postgresql-storage plugin class
23  *
24  *  v. 1.3
25  *  FreeMb logging on disconnects added
26  *
27  *  v. 1.2
28  *  Reconnection on faults added
29  *
30  *  v. 1.1
31  *  tb_stats removed
32  *
33  *  v. 1.0
34  *  Initial implementation
35  *
36  *  $Revision: 1.5 $
37  *  $Date: 2010/01/06 10:43:48 $
38  *
39  */
40
41 #include <string>
42 #include <vector>
43
44 #include <libpq-fe.h>
45
46 #include "stg/module_settings.h"
47 #include "stg/plugin_creator.h"
48 #include "postgresql_store_utils.h"
49 #include "postgresql_store.h"
50
51 namespace
52 {
53 PLUGIN_CREATOR<POSTGRESQL_STORE> pgsc;
54 }
55
56 extern "C" STORE * GetStore();
57
58 //-----------------------------------------------------------------------------
59 STORE * GetStore()
60 {
61 return pgsc.GetPlugin();
62 }
63
64 //-----------------------------------------------------------------------------
65 POSTGRESQL_STORE::POSTGRESQL_STORE()
66     : versionString("postgresql_store v.1.3"),
67       server("localhost"),
68       database("stargazer"),
69       user("stg"),
70       password("123456"),
71       clientEncoding("KOI8"),
72       version(0),
73       retries(3),
74       connection(NULL),
75       logger(GetPluginLogger(GetStgLogger(), "store_postgresql"))
76 {
77 pthread_mutex_init(&mutex, NULL);
78 }
79 //-----------------------------------------------------------------------------
80 POSTGRESQL_STORE::~POSTGRESQL_STORE()
81 {
82 if (connection)
83     {
84     PQfinish(connection);
85     }
86 pthread_mutex_destroy(&mutex);
87 }
88 //-----------------------------------------------------------------------------
89 int POSTGRESQL_STORE::ParseSettings()
90 {
91 std::vector<PARAM_VALUE>::iterator i;
92 std::string s;
93
94 for(i = settings.moduleParams.begin(); i != settings.moduleParams.end(); ++i)
95     {
96     if (i->value.empty())
97         continue;
98     s = ToLower(i->param);
99     if (s == "server")
100         {
101         server = i->value.front();
102         }
103     if (s == "database")
104         {
105         database = i->value.front();
106         }
107     if (s == "user")
108         {
109         user = i->value.front();
110         }
111     if (s == "password")
112         {
113         password = i->value.front();
114         }
115     if (s == "retries")
116         {
117         if (str2x(i->value.front(), retries))
118             {
119             strError = "Invalid 'retries' value";
120             printfd(__FILE__, "POSTGRESQL_STORE::ParseSettings(): '%s'\n", strError.c_str());
121             return -1;
122             }
123         }
124     }
125
126 clientEncoding = "KOI8";
127
128 return Connect();
129 }
130 //-----------------------------------------------------------------------------
131 int POSTGRESQL_STORE::Connect()
132 {
133 std::string params;
134 params = "host=" + server + " "
135        + "dbname=" + database + " "
136        + "user=" + user + " "
137        + "password=" + password;
138
139 connection = PQconnectdb(params.c_str());
140
141 if (PQstatus(connection) != CONNECTION_OK)
142     {
143     strError = PQerrorMessage(connection);
144     printfd(__FILE__, "POSTGRESQL_STORE::Connect(): '%s'\n", strError.c_str());
145     // Will try to connect later
146     return 0;
147     }
148
149 if (PQsetClientEncoding(connection, clientEncoding.c_str()))
150     {
151     strError = PQerrorMessage(connection);
152     printfd(__FILE__, "POSTGRESQL_STORE::Connect(): '%s'\n", strError.c_str());
153     return 1;
154     }
155
156 return CheckVersion();
157 }
158 //-----------------------------------------------------------------------------
159 int POSTGRESQL_STORE::Reset() const
160 {
161 for (int i = 0; i < retries && PQstatus(connection) != CONNECTION_OK; ++i)
162     {
163     struct timespec ts = {1, 0};
164     nanosleep(&ts, NULL);
165     PQreset(connection);
166     }
167
168 if (PQstatus(connection) != CONNECTION_OK)
169     {
170     strError = PQerrorMessage(connection);
171     printfd(__FILE__, "POSTGRESQL_STORE::Reset(): '%s'\n", strError.c_str());
172     return 1;
173     }
174
175 if (PQsetClientEncoding(connection, clientEncoding.c_str()))
176     {
177     strError = PQerrorMessage(connection);
178     printfd(__FILE__, "POSTGRESQL_STORE::Reset(): '%s'\n", strError.c_str());
179     return -1;
180     }
181
182 return CheckVersion();
183 }
184 //-----------------------------------------------------------------------------
185 int POSTGRESQL_STORE::CheckVersion() const
186 {
187
188 if (StartTransaction())
189     {
190     strError = "Failed to start transaction";
191     printfd(__FILE__, "POSTGRESQL_STORE::CheckVersion(): '%s'\n", strError.c_str());
192     return -1;
193     }
194
195 PGresult * result = PQexec(connection, "SELECT MAX(version) FROM tb_info");
196
197 if (PQresultStatus(result) != PGRES_TUPLES_OK)
198     {
199     strError = PQresultErrorMessage(result);
200     PQclear(result);
201     printfd(__FILE__, "POSTGRESQL_STORE::CheckVersion(): '%s'\n");
202     RollbackTransaction();
203     return -1;
204     }
205
206 if (str2x(PQgetvalue(result, 0, 0), version))
207     {
208     strError = "Invalid DB version";
209     PQclear(result);
210     RollbackTransaction();
211     printfd(__FILE__, "POSTGRESQL_STORE::CheckVersion(): '%s'\n", strError.c_str());
212     return -1;
213     }
214
215 PQclear(result);
216
217 if (version < DB_MIN_VERSION)
218     {
219     strError = "DB version too old";
220     RollbackTransaction();
221     printfd(__FILE__, "POSTGRESQL_STORE::CheckVersion(): '%s'\n", strError.c_str());
222     return -1;
223     }
224
225 if (version < 6)
226     {
227     printfd(__FILE__, "POSTGRESQL_STORE::CheckVersion(): I recommend you to upgrade your DB to higher version to support FreeMb logging on disconnect. Current version is %d\n", version);
228     }
229
230 if (CommitTransaction())
231     {
232     strError = "Failed to commit transaction";
233     printfd(__FILE__, "POSTGRESQL_STORE::CheckVersion(): '%s'\n", strError.c_str());
234     return -1;
235     }
236
237 logger("POSTGRESQL_STORE: Current DB schema version: %d", version);
238
239 return 0;
240 }
241 //-----------------------------------------------------------------------------