]> git.stg.codes - stg.git/blob - stargazer/plugins/store/postgresql/postgresql_store.cpp
f3a599a993826b71a70d4731ef7887f48ca1d3fd
[stg.git] / 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 "postgresql_store.h"
42
43 #include "postgresql_store_utils.h"
44 #include "postgresql_store.h"
45
46 #include "stg/module_settings.h"
47 #include "stg/plugin_creator.h"
48
49 #include <string>
50 #include <vector>
51
52 #include <libpq-fe.h>
53
54 namespace
55 {
56 PLUGIN_CREATOR<POSTGRESQL_STORE> pgsc;
57 }
58
59 extern "C" STORE * GetStore();
60
61 //-----------------------------------------------------------------------------
62 STORE * GetStore()
63 {
64 return pgsc.GetPlugin();
65 }
66
67 //-----------------------------------------------------------------------------
68 POSTGRESQL_STORE::POSTGRESQL_STORE()
69     : versionString("postgresql_store v.1.3"),
70       server("localhost"),
71       database("stargazer"),
72       user("stg"),
73       password("123456"),
74       clientEncoding("KOI8"),
75       version(0),
76       retries(3),
77       connection(NULL),
78       logger(PluginLogger::get("store_postgresql"))
79 {
80 pthread_mutex_init(&mutex, NULL);
81 }
82 //-----------------------------------------------------------------------------
83 POSTGRESQL_STORE::~POSTGRESQL_STORE()
84 {
85 if (connection)
86     {
87     PQfinish(connection);
88     }
89 pthread_mutex_destroy(&mutex);
90 }
91 //-----------------------------------------------------------------------------
92 int POSTGRESQL_STORE::ParseSettings()
93 {
94 std::vector<PARAM_VALUE>::iterator i;
95
96 for(i = settings.moduleParams.begin(); i != settings.moduleParams.end(); ++i)
97     {
98     if (i->value.empty())
99         continue;
100     std::string s = ToLower(i->param);
101     if (s == "server")
102         {
103         server = i->value.front();
104         }
105     if (s == "database")
106         {
107         database = i->value.front();
108         }
109     if (s == "user")
110         {
111         user = i->value.front();
112         }
113     if (s == "password")
114         {
115         password = i->value.front();
116         }
117     if (s == "retries")
118         {
119         if (str2x(i->value.front(), retries))
120             {
121             strError = "Invalid 'retries' value";
122             printfd(__FILE__, "POSTGRESQL_STORE::ParseSettings(): '%s'\n", strError.c_str());
123             return -1;
124             }
125         }
126     }
127
128 clientEncoding = "KOI8";
129
130 return Connect();
131 }
132 //-----------------------------------------------------------------------------
133 int POSTGRESQL_STORE::Connect()
134 {
135 std::string params;
136 params = "host=" + server + " "
137        + "dbname=" + database + " "
138        + "user=" + user + " "
139        + "password=" + password;
140
141 connection = PQconnectdb(params.c_str());
142
143 if (PQstatus(connection) != CONNECTION_OK)
144     {
145     strError = PQerrorMessage(connection);
146     printfd(__FILE__, "POSTGRESQL_STORE::Connect(): '%s'\n", strError.c_str());
147     // Will try to connect later
148     return 0;
149     }
150
151 if (PQsetClientEncoding(connection, clientEncoding.c_str()))
152     {
153     strError = PQerrorMessage(connection);
154     printfd(__FILE__, "POSTGRESQL_STORE::Connect(): '%s'\n", strError.c_str());
155     return 1;
156     }
157
158 return CheckVersion();
159 }
160 //-----------------------------------------------------------------------------
161 int POSTGRESQL_STORE::Reset() const
162 {
163 for (int i = 0; i < retries && PQstatus(connection) != CONNECTION_OK; ++i)
164     {
165     struct timespec ts = {1, 0};
166     nanosleep(&ts, NULL);
167     PQreset(connection);
168     }
169
170 if (PQstatus(connection) != CONNECTION_OK)
171     {
172     strError = PQerrorMessage(connection);
173     printfd(__FILE__, "POSTGRESQL_STORE::Reset(): '%s'\n", strError.c_str());
174     return 1;
175     }
176
177 if (PQsetClientEncoding(connection, clientEncoding.c_str()))
178     {
179     strError = PQerrorMessage(connection);
180     printfd(__FILE__, "POSTGRESQL_STORE::Reset(): '%s'\n", strError.c_str());
181     return -1;
182     }
183
184 return CheckVersion();
185 }
186 //-----------------------------------------------------------------------------
187 int POSTGRESQL_STORE::CheckVersion() const
188 {
189
190 if (StartTransaction())
191     {
192     strError = "Failed to start transaction";
193     printfd(__FILE__, "POSTGRESQL_STORE::CheckVersion(): '%s'\n", strError.c_str());
194     return -1;
195     }
196
197 PGresult * result = PQexec(connection, "SELECT MAX(version) FROM tb_info");
198
199 if (PQresultStatus(result) != PGRES_TUPLES_OK)
200     {
201     strError = PQresultErrorMessage(result);
202     PQclear(result);
203     printfd(__FILE__, "POSTGRESQL_STORE::CheckVersion(): '%s'\n");
204     RollbackTransaction();
205     return -1;
206     }
207
208 if (str2x(PQgetvalue(result, 0, 0), version))
209     {
210     strError = "Invalid DB version";
211     PQclear(result);
212     RollbackTransaction();
213     printfd(__FILE__, "POSTGRESQL_STORE::CheckVersion(): '%s'\n", strError.c_str());
214     return -1;
215     }
216
217 PQclear(result);
218
219 if (version < DB_MIN_VERSION)
220     {
221     strError = "DB version too old";
222     RollbackTransaction();
223     printfd(__FILE__, "POSTGRESQL_STORE::CheckVersion(): '%s'\n", strError.c_str());
224     return -1;
225     }
226
227 if (version < 6)
228     {
229     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);
230     }
231
232 if (CommitTransaction())
233     {
234     strError = "Failed to commit transaction";
235     printfd(__FILE__, "POSTGRESQL_STORE::CheckVersion(): '%s'\n", strError.c_str());
236     return -1;
237     }
238
239 logger("POSTGRESQL_STORE: Current DB schema version: %d", version);
240
241 return 0;
242 }
243 //-----------------------------------------------------------------------------