]> git.stg.codes - stg.git/blob - projects/stargazer/plugins/store/postgresql/postgresql_store.cpp
Userdata can also contain cyrilic symbols.
[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       strError(),
68       server("localhost"),
69       database("stargazer"),
70       user("stg"),
71       password("123456"),
72       clientEncoding("KOI8"),
73       settings(),
74       mutex(),
75       version(0),
76       retries(3),
77       connection(NULL),
78       logger(GetPluginLogger(GetStgLogger(), "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 std::string s;
96
97 for(i = settings.moduleParams.begin(); i != settings.moduleParams.end(); ++i)
98     {
99     s = ToLower(i->param);
100     if (s == "server")
101         {
102         server = *(i->value.begin());
103         }
104     if (s == "database")
105         {
106         database = *(i->value.begin());
107         }
108     if (s == "user")
109         {
110         user = *(i->value.begin());
111         }
112     if (s == "password")
113         {
114         password = *(i->value.begin());
115         }
116     if (s == "retries")
117         {
118         if (str2x(*(i->value.begin()), retries))
119             {
120             strError = "Invalid 'retries' value";
121             printfd(__FILE__, "POSTGRESQL_STORE::ParseSettings(): '%s'\n", strError.c_str());
122             return -1;
123             }
124         }
125     }
126
127 clientEncoding = "KOI8";
128
129 return Connect();
130 }
131 //-----------------------------------------------------------------------------
132 int POSTGRESQL_STORE::Connect()
133 {
134 std::string params;
135 params = "host=" + server + " "
136        + "dbname=" + database + " "
137        + "user=" + user + " "
138        + "password=" + password;
139
140 connection = PQconnectdb(params.c_str());
141
142 if (PQstatus(connection) != CONNECTION_OK)
143     {
144     strError = PQerrorMessage(connection);
145     printfd(__FILE__, "POSTGRESQL_STORE::Connect(): '%s'\n", strError.c_str());
146     // Will try to connect later
147     return 0;
148     }
149
150 if (PQsetClientEncoding(connection, clientEncoding.c_str()))
151     {
152     strError = PQerrorMessage(connection);
153     printfd(__FILE__, "POSTGRESQL_STORE::Connect(): '%s'\n", strError.c_str());
154     return 1;
155     }
156
157 return CheckVersion();
158 }
159 //-----------------------------------------------------------------------------
160 int POSTGRESQL_STORE::Reset() const
161 {
162 for (int i = 0; i < retries && PQstatus(connection) != CONNECTION_OK; ++i)
163     {
164     struct timespec ts = {1, 0};
165     nanosleep(&ts, NULL);
166     PQreset(connection);
167     }
168
169 if (PQstatus(connection) != CONNECTION_OK)
170     {
171     strError = PQerrorMessage(connection);
172     printfd(__FILE__, "POSTGRESQL_STORE::Reset(): '%s'\n", strError.c_str());
173     return 1;
174     }
175
176 if (PQsetClientEncoding(connection, clientEncoding.c_str()))
177     {
178     strError = PQerrorMessage(connection);
179     printfd(__FILE__, "POSTGRESQL_STORE::Reset(): '%s'\n", strError.c_str());
180     return -1;
181     }
182
183 return CheckVersion();
184 }
185 //-----------------------------------------------------------------------------
186 int POSTGRESQL_STORE::CheckVersion() const
187 {
188
189 if (StartTransaction())
190     {
191     strError = "Failed to start transaction";
192     printfd(__FILE__, "POSTGRESQL_STORE::CheckVersion(): '%s'\n", strError.c_str());
193     return -1;
194     }
195
196 PGresult * result = PQexec(connection, "SELECT MAX(version) FROM tb_info");
197
198 if (PQresultStatus(result) != PGRES_TUPLES_OK)
199     {
200     strError = PQresultErrorMessage(result);
201     PQclear(result);
202     printfd(__FILE__, "POSTGRESQL_STORE::CheckVersion(): '%s'\n");
203     RollbackTransaction();
204     return -1;
205     }
206
207 if (str2x(PQgetvalue(result, 0, 0), version))
208     {
209     strError = "Invalid DB version";
210     PQclear(result);
211     RollbackTransaction();
212     printfd(__FILE__, "POSTGRESQL_STORE::CheckVersion(): '%s'\n", strError.c_str());
213     return -1;
214     }
215
216 PQclear(result);
217
218 if (version < DB_MIN_VERSION)
219     {
220     strError = "DB version too old";
221     RollbackTransaction();
222     printfd(__FILE__, "POSTGRESQL_STORE::CheckVersion(): '%s'\n", strError.c_str());
223     return -1;
224     }
225
226 if (version < 6)
227     {
228     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);
229     }
230
231 if (CommitTransaction())
232     {
233     strError = "Failed to commit transaction";
234     printfd(__FILE__, "POSTGRESQL_STORE::CheckVersion(): '%s'\n", strError.c_str());
235     return -1;
236     }
237
238 logger("POSTGRESQL_STORE: Current DB schema version: %d", version);
239
240 return 0;
241 }
242 //-----------------------------------------------------------------------------