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