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