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