]> git.stg.codes - stg.git/blob - projects/stargazer/plugins/store/postgresql/postgresql_store_users.cpp
Build and test in both Debug and Release mode.
[stg.git] / projects / stargazer / plugins / store / postgresql / postgresql_store_users.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  *  User manipulation methods
23  *
24  *  $Revision: 1.14 $
25  *  $Date: 2010/05/07 07:26:36 $
26  *
27  */
28
29 #include "postgresql_store.h"
30
31 #include "stg/user_conf.h"
32 #include "stg/user_stat.h"
33 #include "stg/user_ips.h"
34 #include "stg/user_traff.h"
35 #include "stg/common.h"
36 #include "stg/const.h"
37 #include "stg/locker.h"
38 #include "../../../stg_timer.h"
39
40 #include <string>
41 #include <vector>
42 #include <sstream>
43 #include <ctime>
44
45 #include <libpq-fe.h>
46
47 //-----------------------------------------------------------------------------
48 int POSTGRESQL_STORE::GetUsersList(std::vector<std::string> * usersList) const
49 {
50 STG_LOCKER lock(&mutex);
51
52 if (PQstatus(connection) != CONNECTION_OK)
53     {
54     printfd(__FILE__, "POSTGRESQL_STORE::GetUsersList(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
55     if (Reset())
56         {
57         strError = "Connection lost";
58         printfd(__FILE__, "POSTGRESQL_STORE::GetUsersList(): '%s'\n", strError.c_str());
59         return -1;
60         }
61     }
62
63 PGresult * result;
64
65 if (StartTransaction())
66     {
67     printfd(__FILE__, "POSTGRESQL_STORE::GetUsersList(): 'Failed to start transaction'\n");
68     return -1;
69     }
70
71 result = PQexec(connection, "SELECT name FROM tb_users");
72
73 if (PQresultStatus(result) != PGRES_TUPLES_OK)
74     {
75     strError = PQresultErrorMessage(result);
76     PQclear(result);
77     printfd(__FILE__, "POSTGRESQL_STORE::GetUsersList(): '%s'\n", strError.c_str());
78     if (RollbackTransaction())
79         {
80         printfd(__FILE__, "POSTGRESQL_STORE::GetUsersList(): 'Failed to rollback transaction'\n");
81         }
82     return -1;
83     }
84
85 int tuples = PQntuples(result);
86
87 for (int i = 0; i < tuples; ++i)
88     {
89     usersList->push_back(PQgetvalue(result, i, 0));
90     }
91
92 PQclear(result);
93
94 if (CommitTransaction())
95     {
96     printfd(__FILE__, "POSTGRESQL_STORE::GetUsersList(): 'Failed to commit transaction'\n");
97     return -1;
98     }
99
100 return 0;
101 }
102
103 //-----------------------------------------------------------------------------
104 int POSTGRESQL_STORE::AddUser(const std::string & name) const
105 {
106 STG_LOCKER lock(&mutex);
107
108 if (PQstatus(connection) != CONNECTION_OK)
109     {
110     printfd(__FILE__, "POSTGRESQL_STORE::AddUser(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
111     if (Reset())
112         {
113         strError = "Connection lost";
114         printfd(__FILE__, "POSTGRESQL_STORE::AddUser(): '%s'\n", strError.c_str());
115         return -1;
116         }
117     }
118
119 PGresult * result;
120
121 if (StartTransaction())
122     {
123     printfd(__FILE__, "POSTGRESQL_STORE::AddUser(): 'Failed to start transaction'\n");
124     return -1;
125     }
126
127 std::string elogin = name;
128
129 if (EscapeString(elogin))
130     {
131     printfd(__FILE__, "POSTGRESQL_STORE::AddUser(): 'Failed to escape login'\n");
132     if (RollbackTransaction())
133         {
134         printfd(__FILE__, "POSTGRESQL_STORE::AddUser(): 'Failed to rollback transaction'\n");
135         }
136     return -1;
137     }
138
139 std::ostringstream query;
140 query << "SELECT sp_add_user('" << elogin << "')";
141
142 result = PQexec(connection, query.str().c_str());
143
144 if (PQresultStatus(result) != PGRES_TUPLES_OK)
145     {
146     strError = PQresultErrorMessage(result);
147     PQclear(result);
148     printfd(__FILE__, "POSTGRESQL_STORE::AddUser(): '%s'\n", strError.c_str());
149     if (RollbackTransaction())
150         {
151         printfd(__FILE__, "POSTGRESQL_STORE::AddUser(): 'Failed to rollback transaction'\n");
152         }
153     return -1;
154     }
155
156 PQclear(result);
157
158 if (CommitTransaction())
159     {
160     printfd(__FILE__, "POSTGRESQL_STORE::AddUser(): 'Failed to commit transaction'\n");
161     return -1;
162     }
163
164 return 0;
165 }
166
167 //-----------------------------------------------------------------------------
168 int POSTGRESQL_STORE::DelUser(const std::string & login) const
169 {
170 STG_LOCKER lock(&mutex);
171
172 if (PQstatus(connection) != CONNECTION_OK)
173     {
174     printfd(__FILE__, "POSTGRESQL_STORE::DelUser(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
175     if (Reset())
176         {
177         strError = "Connection lost";
178         printfd(__FILE__, "POSTGRESQL_STORE::DelUser(): '%s'\n", strError.c_str());
179         return -1;
180         }
181     }
182
183 PGresult * result;
184
185 if (StartTransaction())
186     {
187     printfd(__FILE__, "POSTGRESQL_STORE::DelUser(): 'Failed to start transaction'\n");
188     return -1;
189     }
190
191 std::string elogin = login;
192
193 if (EscapeString(elogin))
194     {
195     printfd(__FILE__, "POSTGRESQL_STORE::DelUser(): 'Failed to escape login'\n");
196     if (RollbackTransaction())
197         {
198         printfd(__FILE__, "POSTGRESQL_STORE::DelUser(): 'Failed to rollback transaction'\n");
199         }
200     return -1;
201     }
202
203 std::ostringstream query;
204 query << "DELETE FROM tb_users WHERE name = '" << elogin << "'";
205
206 result = PQexec(connection, query.str().c_str());
207
208 if (PQresultStatus(result) != PGRES_COMMAND_OK)
209     {
210     strError = PQresultErrorMessage(result);
211     PQclear(result);
212     printfd(__FILE__, "POSTGRESQL_STORE::DelUser(): '%s'\n", strError.c_str());
213     if (RollbackTransaction())
214         {
215         printfd(__FILE__, "POSTGRESQL_STORE::DelUser(): 'Failed to rollback transaction'\n");
216         }
217     return -1;
218     }
219
220 PQclear(result);
221
222 if (CommitTransaction())
223     {
224     printfd(__FILE__, "POSTGRESQL_STORE::DelUser(): 'Failed to commit transaction'\n");
225     return -1;
226     }
227
228 return 0;
229 }
230 //-----------------------------------------------------------------------------
231 int POSTGRESQL_STORE::SaveUserStat(const STG::UserStat & stat,
232                                    const std::string & login) const
233 {
234 STG_LOCKER lock(&mutex);
235
236 return SaveStat(stat, login);
237 }
238 //-----------------------------------------------------------------------------
239 int POSTGRESQL_STORE::SaveStat(const STG::UserStat & stat,
240                                const std::string & login,
241                                int year,
242                                int month) const
243 {
244 if (PQstatus(connection) != CONNECTION_OK)
245     {
246     printfd(__FILE__, "POSTGRESQL_STORE::SaveStat(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
247     if (Reset())
248         {
249         strError = "Connection lost";
250         printfd(__FILE__, "POSTGRESQL_STORE::SaveStat(): '%s'\n", strError.c_str());
251         return -1;
252         }
253     }
254
255 PGresult * result;
256
257 if (StartTransaction())
258     {
259     printfd(__FILE__, "POSTGRESQL_STORE::SaveStat(): 'Failed to start transaction'\n");
260     return -1;
261     }
262
263 std::string elogin = login;
264
265 if (EscapeString(elogin))
266     {
267     printfd(__FILE__, "POSTGRESQL_STORE::SaveStat(): 'Failed to escape login'\n");
268     if (RollbackTransaction())
269         {
270         printfd(__FILE__, "POSTGRESQL_STORE::SaveStat(): 'Failed to rollback transaction'\n");
271         }
272     return -1;
273     }
274
275 std::ostringstream query;
276 query << "UPDATE tb_users SET "
277             "cash = " << stat.cash << ", "
278             "free_mb = " << stat.freeMb << ", "
279             "last_activity_time = CAST('" << formatTime(stat.lastActivityTime) << "' AS TIMESTAMP), "
280             "last_cash_add = " << stat.lastCashAdd << ", "
281             "last_cash_add_time = CAST('" << formatTime(stat.lastCashAddTime) << "' AS TIMESTAMP), "
282             "passive_time = " << stat.passiveTime << " "
283          "WHERE name = '" << elogin << "'";
284
285 result = PQexec(connection, query.str().c_str());
286
287 if (PQresultStatus(result) != PGRES_COMMAND_OK)
288     {
289     strError = PQresultErrorMessage(result);
290     PQclear(result);
291     printfd(__FILE__, "POSTGRESQL_STORE::SaveStat(): '%s'\n", strError.c_str());
292     if (RollbackTransaction())
293         {
294         printfd(__FILE__, "POSTGRESQL_STORE::SaveStat(): 'Failed to rollback transaction'\n");
295         }
296     return -1;
297     }
298
299 PQclear(result);
300
301 std::string date;
302
303 MakeDate(date, year, month);
304
305 for (int dir = 0; dir < DIR_NUM; ++dir)
306     {
307     query.str("");
308     query << "SELECT sp_add_stats_traffic ("
309                 "'" << elogin << "', "
310                 "CAST('" << date << "' AS DATE), "
311                 "CAST(" << dir << " AS SMALLINT), "
312                 "CAST(" << stat.monthUp[dir] << " AS BIGINT), "
313                 "CAST(" << stat.monthDown[dir] << " AS BIGINT))";
314
315     result = PQexec(connection, query.str().c_str());
316
317     if (PQresultStatus(result) != PGRES_TUPLES_OK)
318         {
319         strError = PQresultErrorMessage(result);
320         PQclear(result);
321         printfd(__FILE__, "POSTGRESQL_STORE::SaveStat(): '%s'\n", strError.c_str());
322         if (RollbackTransaction())
323             {
324             printfd(__FILE__, "POSTGRESQL_STORE::SaveStat(): 'Failed to rollback transaction'\n");
325             }
326         return -1;
327         }
328
329     PQclear(result);
330     }
331
332 if (CommitTransaction())
333     {
334     printfd(__FILE__, "POSTGRESQL_STORE::SaveStat(): 'Failed to commit transaction'\n");
335     return -1;
336     }
337
338 return 0;
339 }
340
341 //-----------------------------------------------------------------------------
342 int POSTGRESQL_STORE::SaveUserConf(const STG::UserConf & conf,
343                                  const std::string & login) const
344 {
345 STG_LOCKER lock(&mutex);
346
347 if (PQstatus(connection) != CONNECTION_OK)
348     {
349     printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
350     if (Reset())
351         {
352         strError = "Connection lost";
353         printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): '%s'\n", strError.c_str());
354         return -1;
355         }
356     }
357
358 PGresult * result;
359
360 if (StartTransaction())
361     {
362     printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to start transaction'\n");
363     return -1;
364     }
365
366 std::string elogin = login;
367
368 if (EscapeString(elogin))
369     {
370     printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape login'\n");
371     if (RollbackTransaction())
372         {
373         printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
374         }
375     return -1;
376     }
377
378 std::ostringstream query;
379 query << "SELECT pk_user FROM tb_users WHERE name = '" << elogin << "'";
380
381 result = PQexec(connection, query.str().c_str());
382
383 if (PQresultStatus(result) != PGRES_TUPLES_OK)
384     {
385     strError = PQresultErrorMessage(result);
386     PQclear(result);
387     printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): '%s'\n", strError.c_str());
388     if (RollbackTransaction())
389         {
390         printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
391         }
392     return -1;
393     }
394
395 int tuples = PQntuples(result);
396
397 if (tuples != 1)
398     {
399     strError = "Failed to fetch user's ID";
400     printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Invalid number of tuples. Wanted 1, actulally %d'\n", tuples);
401     PQclear(result);
402     if (RollbackTransaction())
403         {
404         printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
405         }
406     return -1;
407     }
408
409 uint32_t uid;
410
411     {
412     std::stringstream tuple;
413     tuple << PQgetvalue(result, 0, 0);
414
415     PQclear(result);
416
417     tuple >> uid;
418     }
419
420 std::string eaddress = conf.address;
421 std::string eemail = conf.email;
422 std::string egroup = conf.group;
423 std::string enote = conf.note;
424 std::string epassword = conf.password;
425 std::string ephone = conf.phone;
426 std::string erealname = conf.realName;
427 std::string etariffname = conf.tariffName;
428 std::string enexttariff = conf.nextTariff;
429 std::string ecorporation = conf.corp;
430
431 if (EscapeString(eaddress))
432     {
433     printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape address'\n");
434     if (RollbackTransaction())
435         {
436         printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
437         }
438     return -1;
439     }
440
441 if (EscapeString(eemail))
442     {
443     printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape email'\n");
444     if (RollbackTransaction())
445         {
446         printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
447         }
448     return -1;
449     }
450
451 if (EscapeString(egroup))
452     {
453     printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape group'\n");
454     if (RollbackTransaction())
455         {
456         printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
457         }
458     return -1;
459     }
460
461 if (EscapeString(enote))
462     {
463     printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape note'\n");
464     if (RollbackTransaction())
465         {
466         printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
467         }
468     return -1;
469     }
470
471 if (EscapeString(epassword))
472     {
473     printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape password'\n");
474     if (RollbackTransaction())
475         {
476         printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
477         }
478     return -1;
479     }
480
481 if (EscapeString(ephone))
482     {
483     printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape phone'\n");
484     if (RollbackTransaction())
485         {
486         printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
487         }
488     return -1;
489     }
490
491 if (EscapeString(erealname))
492     {
493     printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape real name'\n");
494     if (RollbackTransaction())
495         {
496         printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
497         }
498     return -1;
499     }
500
501 if (EscapeString(etariffname))
502     {
503     printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape tariff name'\n");
504     if (RollbackTransaction())
505         {
506         printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
507         }
508     return -1;
509     }
510
511 if (EscapeString(enexttariff))
512     {
513     printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape next tariff name'\n");
514     if (RollbackTransaction())
515         {
516         printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
517         }
518     return -1;
519     }
520
521 if (EscapeString(ecorporation))
522     {
523     printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to escape corporation name'\n");
524     if (RollbackTransaction())
525         {
526         printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
527         }
528     return -1;
529     }
530
531 query.str("");
532 query << "UPDATE tb_users SET "
533              "address = '" << eaddress << "', "
534              "always_online = " << (conf.alwaysOnline ? "'t'" : "'f'") << ", "
535              "credit = " << conf.credit << ", "
536              "credit_expire = CAST('" << formatTime(conf.creditExpire) << "' AS TIMESTAMP), "
537              "disabled = " << (conf.disabled ? "'t'" : "'f'") << ", "
538              "disabled_detail_stat = " << (conf.disabledDetailStat ? "'t'" : "'f'") << ", "
539              "email = '" << eemail << "', "
540              "grp = '" << egroup << "', "
541              "note = '" << enote << "', "
542              "passive = " << (conf.passive ? "'t'" : "'f'") << ", "
543              "passwd = '" << epassword << "', "
544              "phone = '" << ephone << "', "
545              "real_name = '" << erealname << "', "
546              "fk_tariff = (SELECT pk_tariff "
547                    "FROM tb_tariffs "
548                    "WHERE name = '" << etariffname << "'), "
549              "fk_tariff_change = (SELECT pk_tariff "
550                    "FROM tb_tariffs "
551                    "WHERE name = '" << enexttariff << "'), "
552              "fk_corporation = (SELECT pk_corporation "
553                    "FROM tb_corporations "
554                    "WHERE name = '" << ecorporation << "') "
555          "WHERE pk_user = " << uid;
556
557 result = PQexec(connection, query.str().c_str());
558
559 if (PQresultStatus(result) != PGRES_COMMAND_OK)
560     {
561     strError = PQresultErrorMessage(result);
562     PQclear(result);
563     printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): '%s'\n", strError.c_str());
564     if (RollbackTransaction())
565         {
566         printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
567         }
568     return -1;
569     }
570
571 PQclear(result);
572
573 if (SaveUserServices(uid, conf.services))
574     {
575     printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to save user's services'\n");
576     if (RollbackTransaction())
577         {
578         printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
579         }
580     return -1;
581     }
582
583 if (SaveUserData(uid, conf.userdata))
584     {
585     printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to save user's data'\n");
586     if (RollbackTransaction())
587         {
588         printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
589         }
590     return -1;
591     }
592
593 if (SaveUserIPs(uid, conf.ips))
594     {
595     printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to save user's IPs'\n");
596     if (RollbackTransaction())
597         {
598         printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to rollback transaction'\n");
599         }
600     return -1;
601     }
602
603 if (CommitTransaction())
604     {
605     printfd(__FILE__, "POSTGRESQL_STORE::SaveUserConf(): 'Failed to commit transaction'\n");
606     return -1;
607     }
608
609 return 0;
610 }
611
612 //-----------------------------------------------------------------------------
613 int POSTGRESQL_STORE::RestoreUserStat(STG::UserStat * stat,
614                                     const std::string & login) const
615 {
616 STG_LOCKER lock(&mutex);
617
618 if (PQstatus(connection) != CONNECTION_OK)
619     {
620     printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
621     if (Reset())
622         {
623         strError = "Connection lost";
624         printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): '%s'\n", strError.c_str());
625         return -1;
626         }
627     }
628
629 PGresult * result;
630
631 if (StartTransaction())
632     {
633     printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Failed to start transaction'\n");
634     return -1;
635     }
636
637 std::string elogin = login;
638
639 if (EscapeString(elogin))
640     {
641     printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Failed to escape login'\n");
642     if (RollbackTransaction())
643         {
644         printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Failed to rollback transaction'\n");
645         }
646     return -1;
647     }
648
649     {
650     std::ostringstream query;
651     query << "SELECT cash, free_mb, "
652                 "last_activity_time, last_cash_add, "
653                 "last_cash_add_time, passive_time "
654              "FROM tb_users "
655              "WHERE name = '" << elogin << "'";
656
657     result = PQexec(connection, query.str().c_str());
658     }
659
660 if (PQresultStatus(result) != PGRES_TUPLES_OK)
661     {
662     strError = PQresultErrorMessage(result);
663     printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): '%s'\n", strError.c_str());
664     PQclear(result);
665     if (RollbackTransaction())
666         {
667         printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Failed to rollback transaction'\n");
668         }
669     return -1;
670     }
671
672 int tuples = PQntuples(result);
673
674 if (tuples != 1)
675     {
676     strError = "Failed to fetch user's stat";
677     printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Invalid number of tuples. Wanted 1, actulally %d'\n", tuples);
678     PQclear(result);
679     if (RollbackTransaction())
680         {
681         printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Failed to rollback transaction'\n");
682         }
683     return -1;
684     }
685
686     {
687     std::stringstream tuple;
688     tuple << PQgetvalue(result, 0, 0) << " ";
689     tuple << PQgetvalue(result, 0, 1) << " ";
690     stat->lastActivityTime = readTime(PQgetvalue(result, 0, 2));
691     tuple << PQgetvalue(result, 0, 3) << " ";
692     stat->lastCashAddTime = readTime(PQgetvalue(result, 0, 4));
693     tuple << PQgetvalue(result, 0, 5) << " ";
694
695     PQclear(result);
696
697     tuple >> stat->cash
698           >> stat->freeMb
699           >> stat->lastCashAdd
700           >> stat->passiveTime;
701     }
702
703     {
704     std::ostringstream query;
705     query << "SELECT dir_num, upload, download "
706              "FROM tb_stats_traffic "
707              "WHERE fk_user IN (SELECT pk_user FROM tb_users WHERE name = '" << elogin << "') AND "
708                    "DATE_TRUNC('month', stats_date) = DATE_TRUNC('month', CAST('" << formatTime(stgTime) << "' AS TIMESTAMP))";
709
710     result = PQexec(connection, query.str().c_str());
711     }
712
713 if (PQresultStatus(result) != PGRES_TUPLES_OK)
714     {
715     strError = PQresultErrorMessage(result);
716     printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): '%s'\n", strError.c_str());
717     PQclear(result);
718     if (RollbackTransaction())
719         {
720         printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Failed to rollback transaction'\n");
721         }
722     return -1;
723     }
724
725 tuples = PQntuples(result);
726
727 for (int i = 0; i < tuples; ++i)
728     {
729     std::stringstream tuple;
730     tuple << PQgetvalue(result, i, 0) << " ";
731     tuple << PQgetvalue(result, i, 1) << " ";
732     tuple << PQgetvalue(result, i, 2) << " ";
733
734     int dir;
735
736     tuple >> dir;
737     tuple >> stat->monthUp[dir];
738     tuple >> stat->monthDown[dir];
739     }
740
741 PQclear(result);
742
743 if (CommitTransaction())
744     {
745     printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Failed to commit transaction'\n");
746     return -1;
747     }
748
749 return 0;
750 }
751
752 //-----------------------------------------------------------------------------
753 int POSTGRESQL_STORE::RestoreUserConf(STG::UserConf * conf,
754                                     const std::string & login) const
755 {
756 STG_LOCKER lock(&mutex);
757
758 if (PQstatus(connection) != CONNECTION_OK)
759     {
760     printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
761     if (Reset())
762         {
763         strError = "Connection lost";
764         printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): '%s'\n", strError.c_str());
765         return -1;
766         }
767     }
768
769 PGresult * result;
770
771 if (StartTransaction())
772     {
773     printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Failed to start transaction'\n");
774     return -1;
775     }
776
777 std::string elogin = login;
778
779 if (EscapeString(elogin))
780     {
781     printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Failed to escape login'\n");
782     if (RollbackTransaction())
783         {
784         printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserStat(): 'Failed to rollback transaction'\n");
785         }
786     return -1;
787     }
788
789     {
790     std::ostringstream query;
791     query << "SELECT tb_users.pk_user, tb_users.address, tb_users.always_online, "
792                     "tb_users.credit, tb_users.credit_expire, tb_users.disabled, "
793                     "tb_users.disabled_detail_stat, tb_users.email, tb_users.grp, "
794                     "tb_users.note, tb_users.passive, tb_users.passwd, tb_users.phone, "
795                     "tb_users.real_name, tf1.name, tf2.name, tb_corporations.name "
796              "FROM tb_users LEFT JOIN tb_tariffs AS tf1 "
797                                 "ON tf1.pk_tariff = tb_users.fk_tariff "
798                            "LEFT JOIN tb_tariffs AS tf2 "
799                                 "ON tf2.pk_tariff = tb_users.fk_tariff_change "
800                            "LEFT JOIN tb_corporations "
801                                 "ON tb_corporations.pk_corporation = tb_users.fk_corporation "
802              "WHERE tb_users.name = '" << elogin << "'";
803
804     result = PQexec(connection, query.str().c_str());
805     }
806
807 if (PQresultStatus(result) != PGRES_TUPLES_OK)
808     {
809     strError = PQresultErrorMessage(result);
810     printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): '%s'\n", strError.c_str());
811     PQclear(result);
812     if (RollbackTransaction())
813         {
814         printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): 'Failed to rollback transaction'\n");
815         }
816     return -1;
817     }
818
819 int tuples = PQntuples(result);
820
821 if (tuples != 1)
822     {
823     strError = "Failed to fetch user's stat";
824     printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): 'Invalid number of tuples. Wanted 1, actulally %d'\n", tuples);
825     PQclear(result);
826     if (RollbackTransaction())
827         {
828         printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): 'Failed to rollback transaction'\n");
829         }
830     return -1;
831     }
832
833 uint32_t uid;
834
835     {
836     std::stringstream tuple;
837     tuple << PQgetvalue(result, 0, 0) << " ";               // uid
838     conf->address = PQgetvalue(result, 0, 1);               // address
839     conf->alwaysOnline = !strncmp(PQgetvalue(result, 0, 2), "t", 1);
840     tuple << PQgetvalue(result, 0, 3) << " ";               // credit
841     conf->creditExpire = readTime(PQgetvalue(result, 0, 4));  // creditExpire
842     conf->disabled = !strncmp(PQgetvalue(result, 0, 5), "t", 1);
843     conf->disabledDetailStat = !strncmp(PQgetvalue(result, 0, 6), "t", 1);
844     conf->email = PQgetvalue(result, 0, 7);                 // email
845     conf->group = PQgetvalue(result, 0, 8);                 // group
846     conf->note = PQgetvalue(result, 0, 9);                  // note
847     conf->passive = !strncmp(PQgetvalue(result, 0, 10), "t", 1);
848     conf->password = PQgetvalue(result, 0, 11);             // password
849     conf->phone = PQgetvalue(result, 0, 12);                // phone
850     conf->realName = PQgetvalue(result, 0, 13);             // realName
851     conf->tariffName = PQgetvalue(result, 0, 14);           // tariffName
852     conf->nextTariff = PQgetvalue(result, 0, 15);           // nextTariff
853     conf->corp = PQgetvalue(result, 0, 16);                 // corp
854
855     PQclear(result);
856
857     if (conf->tariffName == "")
858         conf->tariffName = NO_TARIFF_NAME;
859     if (conf->corp == "")
860         conf->corp = NO_CORP_NAME;
861
862     tuple >> uid
863           >> conf->credit;
864     }
865
866     {
867     std::ostringstream query;
868     query << "SELECT name FROM tb_services "
869              "WHERE pk_service IN (SELECT fk_service "
870                                   "FROM tb_users_services "
871                                   "WHERE fk_user = " << uid << ")";
872
873     result = PQexec(connection, query.str().c_str());
874     }
875
876 if (PQresultStatus(result) != PGRES_TUPLES_OK)
877     {
878     strError = PQresultErrorMessage(result);
879     printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): '%s'\n", strError.c_str());
880     PQclear(result);
881     if (RollbackTransaction())
882         {
883         printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): 'Failed to rollback transaction'\n");
884         }
885     return -1;
886     }
887
888 tuples = PQntuples(result);
889
890 for (int i = 0; i < tuples; ++i)
891     {
892     conf->services.push_back(PQgetvalue(result, i, 0));
893     }
894
895 PQclear(result);
896
897     {
898     std::ostringstream query;
899     query << "SELECT num, data "
900              "FROM tb_users_data "
901              "WHERE fk_user = " << uid;
902
903     result = PQexec(connection, query.str().c_str());
904     }
905
906 if (PQresultStatus(result) != PGRES_TUPLES_OK)
907     {
908     strError = PQresultErrorMessage(result);
909     printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): '%s'\n", strError.c_str());
910     PQclear(result);
911     if (RollbackTransaction())
912         {
913         printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): 'Failed to rollback transaction'\n");
914         }
915     return -1;
916     }
917
918 tuples = PQntuples(result);
919
920 for (int i = 0; i < tuples; ++i)
921     {
922     int num;
923     if (str2x(PQgetvalue(result, i, 0), num))
924         {
925         printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): 'Failed to convert string to int'\n");
926         }
927     else
928         {
929         if (num < USERDATA_NUM &&
930             num >= 0)
931             {
932             conf->userdata[num] = PQgetvalue(result, i, 1);
933             }
934         }
935     }
936
937 PQclear(result);
938
939     {
940     std::ostringstream query;
941     query << "SELECT host(ip), masklen(ip) "
942              "FROM tb_allowed_ip "
943              "WHERE fk_user = " << uid;
944
945     result = PQexec(connection, query.str().c_str());
946     }
947
948 if (PQresultStatus(result) != PGRES_TUPLES_OK)
949     {
950     strError = PQresultErrorMessage(result);
951     printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): '%s'\n", strError.c_str());
952     PQclear(result);
953     if (RollbackTransaction())
954         {
955         printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): 'Failed to rollback transaction'\n");
956         }
957     return -1;
958     }
959
960 tuples = PQntuples(result);
961
962 STG::UserIPs ips;
963 for (int i = 0; i < tuples; ++i)
964     {
965     STG::IPMask im;
966
967     im.ip = inet_strington(PQgetvalue(result, i, 0));
968
969     if (str2x(PQgetvalue(result, i, 1), im.mask))
970         {
971         printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): 'Failed to fetch mask'\n");
972         continue;
973         }
974
975     ips.add(im);
976     }
977 conf->ips = ips;
978
979 PQclear(result);
980
981 if (CommitTransaction())
982     {
983     printfd(__FILE__, "POSTGRESQL_STORE::RestoreUserConf(): 'Failed to commit transaction'\n");
984     return -1;
985     }
986
987 return 0;
988 }
989
990 //-----------------------------------------------------------------------------
991 int POSTGRESQL_STORE::WriteUserChgLog(const std::string & login,
992                                     const std::string & admLogin,
993                                     uint32_t admIP,
994                                     const std::string & paramName,
995                                     const std::string & oldValue,
996                                     const std::string & newValue,
997                                     const std::string & message = "") const
998 {
999 STG_LOCKER lock(&mutex);
1000
1001 if (PQstatus(connection) != CONNECTION_OK)
1002     {
1003     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
1004     if (Reset())
1005         {
1006         strError = "Connection lost";
1007         printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): '%s'\n", strError.c_str());
1008         return -1;
1009         }
1010     }
1011
1012 PGresult * result;
1013
1014 if (StartTransaction())
1015     {
1016     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to start transaction'\n");
1017     return -1;
1018     }
1019
1020 std::string elogin(login);
1021 std::string eadminLogin(admLogin);
1022 std::string eparam(paramName);
1023 std::string eold(oldValue);
1024 std::string enew(newValue);
1025 std::string emessage(message);
1026
1027 if (EscapeString(elogin))
1028     {
1029     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to escape login'\n");
1030     if (RollbackTransaction())
1031         {
1032         printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to rollback transaction'\n");
1033         }
1034     return -1;
1035     }
1036
1037 if (EscapeString(eadminLogin))
1038     {
1039     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to escape admin's login'\n");
1040     if (RollbackTransaction())
1041         {
1042         printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to rollback transaction'\n");
1043         }
1044     return -1;
1045     }
1046
1047 if (EscapeString(eparam))
1048     {
1049     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to escape param's name'\n");
1050     if (RollbackTransaction())
1051         {
1052         printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to rollback transaction'\n");
1053         }
1054     return -1;
1055     }
1056
1057 if (EscapeString(eold))
1058     {
1059     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to escape old value'\n");
1060     if (RollbackTransaction())
1061         {
1062         printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to rollback transaction'\n");
1063         }
1064     return -1;
1065     }
1066
1067 if (EscapeString(enew))
1068     {
1069     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to escape new value'\n");
1070     if (RollbackTransaction())
1071         {
1072         printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to rollback transaction'\n");
1073         }
1074     return -1;
1075     }
1076
1077 std::ostringstream query;
1078 query << "SELECT sp_add_param_log_entry("
1079             "'" << elogin << "', "
1080             "'" << eadminLogin << "', CAST('"
1081             << inet_ntostring(admIP) << "/32' AS INET), "
1082             "'" << eparam << "', "
1083             "CAST('" << formatTime(stgTime) << "' AS TIMESTAMP), "
1084             "'" << eold << "', "
1085             "'" << enew << "', "
1086             "'" << emessage << "')";
1087
1088 result = PQexec(connection, query.str().c_str());
1089
1090 if (PQresultStatus(result) != PGRES_TUPLES_OK)
1091     {
1092     strError = PQresultErrorMessage(result);
1093     PQclear(result);
1094     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): '%s'\n", strError.c_str());
1095     if (RollbackTransaction())
1096         {
1097         printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to rollback transaction'\n");
1098         }
1099     return -1;
1100     }
1101
1102 PQclear(result);
1103
1104 if (CommitTransaction())
1105     {
1106     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserChgLog(): 'Failed to commit transaction'\n");
1107     return -1;
1108     }
1109
1110 return 0;
1111 }
1112
1113 //-----------------------------------------------------------------------------
1114 int POSTGRESQL_STORE::WriteUserConnect(const std::string & login, uint32_t ip) const
1115 {
1116 STG_LOCKER lock(&mutex);
1117
1118 if (PQstatus(connection) != CONNECTION_OK)
1119     {
1120     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserConnect(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
1121     if (Reset())
1122         {
1123         strError = "Connection lost";
1124         printfd(__FILE__, "POSTGRESQL_STORE::WriteUserConnect(): '%s'\n", strError.c_str());
1125         return -1;
1126         }
1127     }
1128
1129 PGresult * result;
1130
1131 if (StartTransaction())
1132     {
1133     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserConnect(): 'Failed to start transaction'\n");
1134     return -1;
1135     }
1136
1137 std::string elogin(login);
1138
1139 if (EscapeString(elogin))
1140     {
1141     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserConnect(): 'Failed to escape login'\n");
1142     if (RollbackTransaction())
1143         {
1144         printfd(__FILE__, "POSTGRESQL_STORE::WriteUserConnect(): 'Failed to rollback transaction'\n");
1145         }
1146     return -1;
1147     }
1148
1149 std::ostringstream query;
1150 if (version < 6)
1151     {
1152     query << "SELECT sp_add_session_log_entry("
1153                  "'" << elogin << "', "
1154                  "CAST('" << formatTime(stgTime) << "' AS TIMESTAMP), "
1155                  "'c', CAST('"
1156                  << inet_ntostring(ip) << "/32' AS INET), 0)";
1157     }
1158 else
1159     {
1160     query << "SELECT sp_add_session_log_entry("
1161                  "'" << elogin << "', "
1162                  "CAST('" << formatTime(stgTime) << "' AS TIMESTAMP), "
1163                  "'c', CAST('"
1164                  << inet_ntostring(ip) << "/32' AS INET), 0, 0, '')";
1165     }
1166
1167 result = PQexec(connection, query.str().c_str());
1168
1169 if (PQresultStatus(result) != PGRES_TUPLES_OK)
1170     {
1171     strError = PQresultErrorMessage(result);
1172     PQclear(result);
1173     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserConnect(): '%s'\n", strError.c_str());
1174     if (RollbackTransaction())
1175         {
1176         printfd(__FILE__, "POSTGRESQL_STORE::WriteUserConnect(): 'Failed to rollback transaction'\n");
1177         }
1178     return -1;
1179     }
1180
1181 PQclear(result);
1182
1183 if (CommitTransaction())
1184     {
1185     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserConnect(): 'Failed to commit transaction'\n");
1186     return -1;
1187     }
1188
1189 return 0;
1190 }
1191
1192 //-----------------------------------------------------------------------------
1193 int POSTGRESQL_STORE::WriteUserDisconnect(const std::string & login,
1194                     const STG::DirTraff & monthUp,
1195                     const STG::DirTraff & monthDown,
1196                     const STG::DirTraff & sessionUp,
1197                     const STG::DirTraff & sessionDown,
1198                     double cash,
1199                     double freeMb,
1200                     const std::string & reason) const
1201 {
1202 STG_LOCKER lock(&mutex);
1203
1204 if (PQstatus(connection) != CONNECTION_OK)
1205     {
1206     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
1207     if (Reset())
1208         {
1209         strError = "Connection lost";
1210         printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): '%s'\n", strError.c_str());
1211         return -1;
1212         }
1213     }
1214
1215 PGresult * result;
1216
1217 if (StartTransaction())
1218     {
1219     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to start transaction'\n");
1220     return -1;
1221     }
1222
1223 std::string elogin(login);
1224
1225 if (EscapeString(elogin))
1226     {
1227     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to escape login'\n");
1228     if (RollbackTransaction())
1229         {
1230         printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to rollback transaction'\n");
1231         }
1232     return -1;
1233     }
1234
1235 std::string ereason(reason);
1236
1237 if (EscapeString(ereason))
1238     {
1239     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to escape reason'\n");
1240     if (RollbackTransaction())
1241         {
1242         printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to rollback transaction'\n");
1243         }
1244     return -1;
1245     }
1246
1247     {
1248     std::ostringstream query;
1249     if (version < 6)
1250         {
1251         // Old database version - no freeMb logging support
1252         query << "SELECT sp_add_session_log_entry("
1253                     "'" << elogin << "', "
1254                     "CAST('" << formatTime(stgTime) << "' AS TIMESTAMP), "
1255                     "'d', CAST('0.0.0.0/0' AS INET), "
1256                     << cash << ")";
1257         }
1258     else
1259         {
1260         query << "SELECT sp_add_session_log_entry("
1261                     "'" << elogin << "', "
1262                     "CAST('" << formatTime(stgTime) << "' AS TIMESTAMP), "
1263                     "'d', CAST('0.0.0.0/0' AS INET), "
1264                     << cash << ", " << freeMb << ", '" << ereason << "')";
1265         }
1266
1267     result = PQexec(connection, query.str().c_str());
1268     }
1269
1270 if (PQresultStatus(result) != PGRES_TUPLES_OK)
1271     {
1272     strError = PQresultErrorMessage(result);
1273     PQclear(result);
1274     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): '%s'\n", strError.c_str());
1275     if (RollbackTransaction())
1276         {
1277         printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to rollback transaction'\n");
1278         }
1279     return -1;
1280     }
1281
1282 int tuples = PQntuples(result);
1283
1284 if (tuples != 1)
1285     {
1286     strError = "Failed to fetch session's log ID";
1287     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Invalid number of tuples. Wanted 1, actulally %d'\n", tuples);
1288     PQclear(result);
1289     if (RollbackTransaction())
1290         {
1291         printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to rollback transaction'\n");
1292         }
1293     return -1;
1294     }
1295
1296 uint32_t lid;
1297
1298 if (str2x(PQgetvalue(result, 0, 0), lid))
1299     {
1300     strError = "Failed to convert string to int";
1301     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): '%s'\n", strError.c_str());
1302     PQclear(result);
1303     if (RollbackTransaction())
1304         {
1305         printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to rollback transaction'\n");
1306         }
1307     return -1;
1308     }
1309
1310 PQclear(result);
1311
1312 for (int i = 0; i < DIR_NUM; ++i)
1313     {
1314     std::ostringstream query;
1315     query << "INSERT INTO tb_sessions_data "
1316                 "(fk_session_log, "
1317                  "dir_num, "
1318                  "session_upload, "
1319                  "session_download, "
1320                  "month_upload, "
1321                  "month_download)"
1322              "VALUES ("
1323                 << lid << ", "
1324                 << i << ", "
1325                 << sessionUp[i] << ", "
1326                 << sessionDown[i] << ", "
1327                 << monthUp[i] << ", "
1328                 << monthDown[i] << ")";
1329
1330     result = PQexec(connection, query.str().c_str());
1331
1332     if (PQresultStatus(result) != PGRES_COMMAND_OK)
1333         {
1334         strError = PQresultErrorMessage(result);
1335         PQclear(result);
1336         printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): '%s'\n", strError.c_str());
1337         if (RollbackTransaction())
1338             {
1339             printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to rollback transaction'\n");
1340             }
1341         return -1;
1342         }
1343
1344     PQclear(result);
1345     }
1346
1347 if (CommitTransaction())
1348     {
1349     printfd(__FILE__, "POSTGRESQL_STORE::WriteUserDisconnect(): 'Failed to commit transaction'\n");
1350     return -1;
1351     }
1352
1353 return 0;
1354 }
1355
1356 //-----------------------------------------------------------------------------
1357 int POSTGRESQL_STORE::WriteDetailedStat(const STG::TraffStat & statTree,
1358                                       time_t lastStat,
1359                                       const std::string & login) const
1360 {
1361 STG_LOCKER lock(&mutex);
1362
1363 if (PQstatus(connection) != CONNECTION_OK)
1364     {
1365     printfd(__FILE__, "POSTGRESQL_STORE::WriteDetailedStat(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
1366     if (Reset())
1367         {
1368         strError = "Connection lost";
1369         printfd(__FILE__, "POSTGRESQL_STORE::WriteDetailedStat(): '%s'\n", strError.c_str());
1370         return -1;
1371         }
1372     }
1373
1374 if (StartTransaction())
1375     {
1376     printfd(__FILE__, "POSTGRESQL_STORE::WriteDetailedStat(): 'Failed to start transaction'\n");
1377     return -1;
1378     }
1379
1380 std::string elogin(login);
1381
1382 if (EscapeString(elogin))
1383     {
1384     printfd(__FILE__, "POSTGRESQL_STORE::WriteDetailedStat(): 'Failed to escape login'\n");
1385     if (RollbackTransaction())
1386         {
1387         printfd(__FILE__, "POSTGRESQL_STORE::WriteDetailedStat(): 'Failed to rollback transaction'\n");
1388         }
1389     return -1;
1390     }
1391
1392 STG::TraffStat::const_iterator it;
1393 time_t currTime = time(NULL);
1394
1395 for (it = statTree.begin(); it != statTree.end(); ++it)
1396     {
1397     std::ostringstream query;
1398     query << "INSERT INTO tb_detail_stats "
1399                 "(till_time, from_time, fk_user, "
1400                  "dir_num, ip, download, upload, cost) "
1401              "VALUES ("
1402                 "CAST('" << formatTime(currTime) << "' AS TIMESTAMP), "
1403                 "CAST('" << formatTime(lastStat) << "' AS TIMESTAMP), "
1404                 "(SELECT pk_user FROM tb_users WHERE name = '" << elogin << "'), "
1405                 << it->first.dir << ", "
1406                 << "CAST('" << inet_ntostring(it->first.ip) << "' AS INET), "
1407                 << it->second.down << ", "
1408                 << it->second.up << ", "
1409                 << it->second.cash << ")";
1410
1411     PGresult * result = PQexec(connection, query.str().c_str());
1412
1413     if (PQresultStatus(result) != PGRES_COMMAND_OK)
1414         {
1415         strError = PQresultErrorMessage(result);
1416         PQclear(result);
1417         printfd(__FILE__, "POSTGRESQL_STORE::WriteDetailedStat(): '%s'\n", strError.c_str());
1418         if (RollbackTransaction())
1419             {
1420             printfd(__FILE__, "POSTGRESQL_STORE::WriteDetailedStat(): 'Failed to rollback transaction'\n");
1421             }
1422         return -1;
1423         }
1424
1425     PQclear(result);
1426     }
1427
1428 if (CommitTransaction())
1429     {
1430     printfd(__FILE__, "POSTGRESQL_STORE::WriteDetailedStat(): 'Failed to commit transaction'\n");
1431     return -1;
1432     }
1433
1434 return 0;
1435 }
1436
1437 //-----------------------------------------------------------------------------
1438 int POSTGRESQL_STORE::SaveMonthStat(const STG::UserStat & stat, int month, int year, const std::string & login) const
1439 {
1440 STG_LOCKER lock(&mutex);
1441
1442 return SaveStat(stat, login, year, month);
1443 }
1444
1445 //-----------------------------------------------------------------------------
1446 int POSTGRESQL_STORE::SaveUserServices(uint32_t uid,
1447                                        const std::vector<std::string> & services) const
1448 {
1449 PGresult * result;
1450
1451     {
1452     std::ostringstream query;
1453     query << "DELETE FROM tb_users_services WHERE fk_user = " << uid;
1454
1455     result = PQexec(connection, query.str().c_str());
1456
1457     if (PQresultStatus(result) != PGRES_COMMAND_OK)
1458         {
1459         strError = PQresultErrorMessage(result);
1460         PQclear(result);
1461         printfd(__FILE__, "POSTGRESQL_STORE::SaveUserServices(): '%s'\n", strError.c_str());
1462         return -1;
1463         }
1464
1465     PQclear(result);
1466     }
1467
1468 std::vector<std::string>::const_iterator it;
1469
1470 for (it = services.begin(); it != services.end(); ++it)
1471     {
1472     std::string ename = *it;
1473
1474     if (EscapeString(ename))
1475         {
1476         printfd(__FILE__, "POSTGRESQL_STORE::SaveUserServices(): 'Failed to escape service name'\n");
1477         return -1;
1478         }
1479
1480     std::ostringstream query;
1481     query << "INSERT INTO tb_users_services "
1482                 "(fk_user, fk_service) "
1483              "VALUES "
1484                 "(" << uid << ", "
1485                   "(SELECT pk_service "
1486                    "FROM tb_services "
1487                    "WHERE name = '" << ename << "'))";
1488
1489     result = PQexec(connection, query.str().c_str());
1490
1491     if (PQresultStatus(result) != PGRES_COMMAND_OK)
1492         {
1493         strError = PQresultErrorMessage(result);
1494         PQclear(result);
1495         printfd(__FILE__, "POSTGRESQL_STORE::SaveUserServices(): '%s'\n", strError.c_str());
1496         return -1;
1497         }
1498
1499     PQclear(result);
1500     }
1501
1502 return 0;
1503 }
1504
1505 //-----------------------------------------------------------------------------
1506 int POSTGRESQL_STORE::SaveUserIPs(uint32_t uid,
1507                                   const STG::UserIPs & ips) const
1508 {
1509 PGresult * result;
1510
1511     {
1512     std::ostringstream query;
1513     query << "DELETE FROM tb_allowed_ip WHERE fk_user = " << uid;
1514
1515     result = PQexec(connection, query.str().c_str());
1516     }
1517
1518 if (PQresultStatus(result) != PGRES_COMMAND_OK)
1519     {
1520     strError = PQresultErrorMessage(result);
1521     PQclear(result);
1522     printfd(__FILE__, "POSTGRESQL_STORE::SaveUserIPs(): '%s'\n", strError.c_str());
1523     return -1;
1524     }
1525
1526 PQclear(result);
1527
1528 for (size_t i = 0; i < ips.count(); ++i)
1529     {
1530     std::ostringstream query;
1531     query << "INSERT INTO tb_allowed_ip "
1532                 "(fk_user, ip) "
1533              "VALUES "
1534                 "(" << uid << ", CAST('"
1535                     << inet_ntostring(ips[i].ip) << "/"
1536                     << static_cast<int>(ips[i].mask) << "' AS INET))";
1537
1538     result = PQexec(connection, query.str().c_str());
1539
1540     if (PQresultStatus(result) != PGRES_COMMAND_OK)
1541         {
1542         strError = PQresultErrorMessage(result);
1543         PQclear(result);
1544         printfd(__FILE__, "POSTGRESQL_STORE::SaveUserIPs(): '%s'\n", strError.c_str());
1545         return -1;
1546         }
1547
1548     PQclear(result);
1549     }
1550
1551 return 0;
1552 }
1553
1554 //-----------------------------------------------------------------------------
1555 int POSTGRESQL_STORE::SaveUserData(uint32_t uid,
1556                                    const std::vector<std::string> & data) const
1557 {
1558 for (unsigned i = 0; i < data.size(); ++i)
1559     {
1560     std::string edata = data[i];
1561
1562     if (EscapeString(edata))
1563         {
1564         printfd(__FILE__, "POSTGRESQL_STORE::SaveUserData(): 'Failed to escape userdata field'\n");
1565         return -1;
1566         }
1567
1568     PGresult * result;
1569
1570     std::ostringstream query;
1571     query << "SELECT sp_set_user_data("
1572                 << uid << ", "
1573                 << "CAST(" << i << " AS SMALLINT), "
1574                 << "'" << edata << "')";
1575
1576     result = PQexec(connection, query.str().c_str());
1577
1578     if (PQresultStatus(result) != PGRES_TUPLES_OK)
1579         {
1580         strError = PQresultErrorMessage(result);
1581         PQclear(result);
1582         printfd(__FILE__, "POSTGRESQL_STORE::SaveUserData(): '%s'\n", strError.c_str());
1583         return -1;
1584         }
1585
1586     PQclear(result);
1587     }
1588
1589 return 0;
1590 }
1591