]> git.stg.codes - stg.git/blob - projects/stargazer/plugins/store/postgresql/postgresql_store_tariffs.cpp
Ticket 37. The TARIFF::CHANGE_POLICY changePolicy object added in the
[stg.git] / projects / stargazer / plugins / store / postgresql / postgresql_store_tariffs.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  *  Tariffs manipulation methods
23  *
24  *  $Revision: 1.2 $
25  *  $Date: 2009/06/09 12:32:40 $
26  *
27  */
28
29 #include <string>
30 #include <vector>
31 #include <sstream>
32 #include <cmath>
33
34 #include <libpq-fe.h>
35
36 #include "postgresql_store.h"
37 #include "stg/locker.h"
38
39 namespace
40 {
41
42 const int pt_mega = 1024 * 1024;
43
44 }
45
46 //-----------------------------------------------------------------------------
47 int POSTGRESQL_STORE::GetTariffsList(std::vector<std::string> * tariffsList) const
48 {
49 STG_LOCKER lock(&mutex);
50
51 if (PQstatus(connection) != CONNECTION_OK)
52     {
53     printfd(__FILE__, "POSTGRESQL_STORE::GetTariffsList(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
54     if (Reset())
55         {
56         strError = "Connection lost";
57         printfd(__FILE__, "POSTGRESQL_STORE::GetTariffsList(): '%s'\n", strError.c_str());
58         return -1;
59         }
60     }
61
62 PGresult * result;
63
64 if (StartTransaction())
65     {
66     printfd(__FILE__, "POSTGRESQL_STORE::GetTariffsList(): 'Failed to start transaction'\n");
67     return -1;
68     }
69
70 result = PQexec(connection, "SELECT name FROM tb_tariffs");
71
72 if (PQresultStatus(result) != PGRES_TUPLES_OK)
73     {
74     strError = PQresultErrorMessage(result);
75     PQclear(result);
76     printfd(__FILE__, "POSTGRESQL_STORE::GetTariffsList(): '%s'\n", strError.c_str());
77     if (RollbackTransaction())
78         {
79         printfd(__FILE__, "POSTGRESQL_STORE::GetTariffsList(): 'Failed to rollback transaction'\n");
80         }
81     return -1;
82     }
83
84 int tuples = PQntuples(result);
85
86 for (int i = 0; i < tuples; ++i)
87     {
88     tariffsList->push_back(PQgetvalue(result, i, 0));
89     }
90
91 PQclear(result);
92
93 if (CommitTransaction())
94     {
95     printfd(__FILE__, "POSTGRESQL_STORE::GetTariffsList(): 'Failed to commit transaction'\n");
96     return -1;
97     }
98
99 return 0;
100 }
101
102 //-----------------------------------------------------------------------------
103 int POSTGRESQL_STORE::AddTariff(const std::string & name) const
104 {
105 STG_LOCKER lock(&mutex);
106
107 if (PQstatus(connection) != CONNECTION_OK)
108     {
109     printfd(__FILE__, "POSTGRESQL_STORE::AddTariff(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
110     if (Reset())
111         {
112         strError = "Connection lost";
113         printfd(__FILE__, "POSTGRESQL_STORE::AddTariff(): '%s'\n", strError.c_str());
114         return -1;
115         }
116     }
117
118 PGresult * result;
119
120 if (StartTransaction())
121     {
122     printfd(__FILE__, "POSTGRESQL_STORE::AddTariff(): 'Failed to start transaction'\n");
123     return -1;
124     }
125
126 std::string ename = name;
127
128 if (EscapeString(ename))
129     {
130     printfd(__FILE__, "POSTGRESQL_STORE::AddTariff(): 'Failed to escape name'\n");
131     if (RollbackTransaction())
132         {
133         printfd(__FILE__, "POSTGRESQL_STORE::AddTariff(): 'Failed to rollback transaction'\n");
134         }
135     return -1;
136     }
137
138 std::ostringstream query;
139 query << "SELECT sp_add_tariff('" << ename << "', " << DIR_NUM << ")";
140
141 result = PQexec(connection, query.str().c_str());
142
143 if (PQresultStatus(result) != PGRES_TUPLES_OK)
144     {
145     strError = PQresultErrorMessage(result);
146     PQclear(result);
147     printfd(__FILE__, "POSTGRESQL_STORE::AddTariff(): '%s'\n", strError.c_str());
148     if (RollbackTransaction())
149         {
150         printfd(__FILE__, "POSTGRESQL_STORE::AddTariff(): 'Failed to rollback transaction'\n");
151         }
152     return -1;
153     }
154
155 PQclear(result);
156
157 if (CommitTransaction())
158     {
159     printfd(__FILE__, "POSTGRESQL_STORE::AddTariff(): 'Failed to commit transaction'\n");
160     return -1;
161     }
162
163 return 0;
164 }
165 //-----------------------------------------------------------------------------
166 int POSTGRESQL_STORE::DelTariff(const std::string & name) const
167 {
168 STG_LOCKER lock(&mutex);
169
170 if (PQstatus(connection) != CONNECTION_OK)
171     {
172     printfd(__FILE__, "POSTGRESQL_STORE::DelTariff(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
173     if (Reset())
174         {
175         strError = "Connection lost";
176         printfd(__FILE__, "POSTGRESQL_STORE::DelTariff(): '%s'\n", strError.c_str());
177         return -1;
178         }
179     }
180
181 PGresult * result;
182
183 if (StartTransaction())
184     {
185     printfd(__FILE__, "POSTGRESQL_STORE::DelTariff(): 'Failed to start transaction'\n");
186     return -1;
187     }
188
189 std::string ename = name;
190
191 if (EscapeString(ename))
192     {
193     printfd(__FILE__, "POSTGRESQL_STORE::AddTariff(): 'Failed to escape name'\n");
194     if (RollbackTransaction())
195         {
196         printfd(__FILE__, "POSTGRESQL_STORE::AddTariff(): 'Failed to rollback transaction'\n");
197         }
198     return -1;
199     }
200
201 std::ostringstream query;
202 query << "DELETE FROM tb_tariffs WHERE name = '" << ename << "'";
203
204 result = PQexec(connection, query.str().c_str());
205
206 if (PQresultStatus(result) != PGRES_COMMAND_OK)
207     {
208     strError = PQresultErrorMessage(result);
209     PQclear(result);
210     printfd(__FILE__, "POSTGRESQL_STORE::DelTariff(): '%s'\n", strError.c_str());
211     if (RollbackTransaction())
212         {
213         printfd(__FILE__, "POSTGRESQL_STORE::DelTariff(): 'Failed to rollback transaction'\n");
214         }
215     return -1;
216     }
217
218 PQclear(result);
219
220 if (CommitTransaction())
221     {
222     printfd(__FILE__, "POSTGRESQL_STORE::DelTariff(): 'Failed to commit transaction'\n");
223     return -1;
224     }
225
226 return 0;
227 }
228 //-----------------------------------------------------------------------------
229 int POSTGRESQL_STORE::SaveTariff(const TARIFF_DATA & td,
230                                  const std::string & tariffName) const
231 {
232 STG_LOCKER lock(&mutex);
233
234 if (PQstatus(connection) != CONNECTION_OK)
235     {
236     printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
237     if (Reset())
238         {
239         strError = "Connection lost";
240         printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): '%s'\n", strError.c_str());
241         return -1;
242         }
243     }
244
245 PGresult * result;
246
247 if (StartTransaction())
248     {
249     printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): 'Failed to start transaction'\n");
250     return -1;
251     }
252
253 std::string ename = tariffName;
254
255 if (EscapeString(ename))
256     {
257     printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): 'Failed to escape name'\n");
258     if (RollbackTransaction())
259         {
260         printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): 'Failed to rollback transaction'\n");
261         }
262     return -1;
263     }
264
265     {
266     std::ostringstream query;
267     query << "SELECT pk_tariff FROM tb_tariffs WHERE name = '" << ename << "'";
268
269     result = PQexec(connection, query.str().c_str());
270     }
271
272 if (PQresultStatus(result) != PGRES_TUPLES_OK)
273     {
274     strError = PQresultErrorMessage(result);
275     PQclear(result);
276     printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): '%s'\n", strError.c_str());
277     if (RollbackTransaction())
278         {
279         printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): 'Failed to rollback transaction'\n");
280         }
281     return -1;
282     }
283
284 int tuples = PQntuples(result);
285
286 if (tuples != 1)
287     {
288     strError = "Failed to fetch tariff ID";
289     printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): 'Invalid number of tuples. Wanted 1, actulally %d'\n", tuples);
290     PQclear(result);
291     if (RollbackTransaction())
292         {
293         printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): 'Failed to rollback transaction'\n");
294         }
295     return -1;
296     }
297
298 int32_t id;
299
300     {
301     std::stringstream tuple;
302     tuple << PQgetvalue(result, 0, 0);
303
304     PQclear(result);
305
306     tuple >> id;
307     }
308
309     {
310     std::ostringstream query;
311     query << "UPDATE tb_tariffs SET \
312                   fee = " << td.tariffConf.fee << ", \
313                   free = " << td.tariffConf.free << ", \
314                   passive_cost = " << td.tariffConf.passiveCost << ", \
315                   traff_type = " << td.tariffConf.traffType;
316
317     if (version > 6)
318         query << ", period = '" << TARIFF::PeriodToString(td.tariffConf.period) << "'";
319
320     query << " WHERE pk_tariff = " << id;
321
322     result = PQexec(connection, query.str().c_str());
323     }
324
325 if (PQresultStatus(result) != PGRES_COMMAND_OK)
326     {
327     strError = PQresultErrorMessage(result);
328     PQclear(result);
329     printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): '%s'\n", strError.c_str());
330     if (RollbackTransaction())
331         {
332         printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): 'Failed to rollback transaction'\n");
333         }
334     return -1;
335     }
336
337 PQclear(result);
338
339 for(int i = 0; i < DIR_NUM; i++)
340     {
341     double pda = td.dirPrice[i].priceDayA * 1024 * 1024;
342     double pdb = td.dirPrice[i].priceDayB * 1024 * 1024;
343     double pna = 0;
344     double pnb = 0;
345
346     if (td.dirPrice[i].singlePrice)
347         {
348         pna = pda;
349         pnb = pdb;
350         }
351     else
352         {
353         pna = td.dirPrice[i].priceNightA * 1024 * 1024;
354         pnb = td.dirPrice[i].priceNightB * 1024 * 1024;
355         }
356
357     int threshold = 0;
358     if (td.dirPrice[i].noDiscount)
359         {
360         threshold = 0xffFFffFF;
361         }
362     else
363         {
364         threshold = td.dirPrice[i].threshold;
365         }
366
367         {
368         std::ostringstream query;
369         query << "UPDATE tb_tariffs_params SET \
370                       price_day_a = " << pda << ", \
371                       price_day_b = " << pdb << ", \
372                       price_night_a = " << pna << ", \
373                       price_night_b = " << pnb << ", \
374                       threshold = " << threshold << ", \
375                       time_day_begins = CAST('" << td.dirPrice[i].hDay
376                                                 << ":"
377                                                 << td.dirPrice[i].mDay << "' AS TIME), \
378                       time_day_ends = CAST('" << td.dirPrice[i].hNight
379                                               << ":"
380                                               << td.dirPrice[i].mNight << "' AS TIME) \
381                  WHERE fk_tariff = " << id << " AND dir_num = " << i;
382
383         result = PQexec(connection, query.str().c_str());
384         }
385
386     if (PQresultStatus(result) != PGRES_COMMAND_OK)
387         {
388         strError = PQresultErrorMessage(result);
389         PQclear(result);
390         printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): '%s'\n", strError.c_str());
391         if (RollbackTransaction())
392             {
393             printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): 'Failed to rollback transaction'\n");
394             }
395         return -1;
396         }
397
398     PQclear(result);
399     }
400
401 if (CommitTransaction())
402     {
403     printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): 'Failed to commit transaction'\n");
404     return -1;
405     }
406
407 return 0;
408 }
409 //-----------------------------------------------------------------------------
410 int POSTGRESQL_STORE::RestoreTariff(TARIFF_DATA * td,
411                                   const std::string & tariffName) const
412 {
413 STG_LOCKER lock(&mutex);
414
415 if (PQstatus(connection) != CONNECTION_OK)
416     {
417     printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
418     if (Reset())
419         {
420         strError = "Connection lost";
421         printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): '%s'\n", strError.c_str());
422         return -1;
423         }
424     }
425
426 PGresult * result;
427
428 if (StartTransaction())
429     {
430     printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Failed to start transaction'\n");
431     return -1;
432     }
433
434 std::string ename = tariffName;
435
436 if (EscapeString(ename))
437     {
438     printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Failed to escape name'\n");
439     if (RollbackTransaction())
440         {
441         printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Failed to rollback transaction'\n");
442         }
443     return -1;
444     }
445
446 td->tariffConf.name = tariffName;
447
448 std::ostringstream query;
449 query << "SELECT pk_tariff, \
450                  fee, \
451                  free, \
452                  passive_cost, \
453                  traff_type";
454
455 if (version > 6)
456     query << ", period";
457
458 query << " FROM tb_tariffs WHERE name = '" << ename << "'";
459
460 result = PQexec(connection, query.str().c_str());
461
462 if (PQresultStatus(result) != PGRES_TUPLES_OK)
463     {
464     strError = PQresultErrorMessage(result);
465     PQclear(result);
466     printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): '%s'\n", strError.c_str());
467     if (RollbackTransaction())
468         {
469         printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Failed to rollback transaction'\n");
470         }
471     return -1;
472     }
473
474 int tuples = PQntuples(result);
475
476 if (tuples != 1)
477     {
478     strError = "Failed to fetch tariff data";
479     printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Invalid number of tuples. Wanted 1, actulally %d'\n", tuples);
480     PQclear(result);
481     if (RollbackTransaction())
482         {
483         printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Failed to rollback transaction'\n");
484         }
485     return -1;
486     }
487
488 int id;
489
490     {
491     std::stringstream tuple;
492     tuple << PQgetvalue(result, 0, 0) << " ";
493     tuple << PQgetvalue(result, 0, 1) << " ";
494     tuple << PQgetvalue(result, 0, 2) << " ";
495     tuple << PQgetvalue(result, 0, 3) << " ";
496     tuple << PQgetvalue(result, 0, 4) << " ";
497
498     tuple >> id;
499     tuple >> td->tariffConf.fee;
500     tuple >> td->tariffConf.free;
501     tuple >> td->tariffConf.passiveCost;
502     tuple >> td->tariffConf.traffType;
503     }
504
505 if (version > 6)
506     td->tariffConf.period = TARIFF::StringToPeriod(PQgetvalue(result, 0, 5));
507
508 PQclear(result);
509
510 query.str("");
511 query << "SELECT dir_num, \
512                  price_day_a, \
513                  price_day_b, \
514                  price_night_a, \
515                  price_night_b, \
516                  threshold, \
517                  EXTRACT(hour FROM time_day_begins), \
518                  EXTRACT(minute FROM time_day_begins), \
519                  EXTRACT(hour FROM time_day_ends), \
520                  EXTRACT(minute FROM time_day_ends) \
521           FROM tb_tariffs_params \
522           WHERE fk_tariff = " << id;
523
524 result = PQexec(connection, query.str().c_str());
525
526 if (PQresultStatus(result) != PGRES_TUPLES_OK)
527     {
528     strError = PQresultErrorMessage(result);
529     PQclear(result);
530     printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): '%s'\n", strError.c_str());
531     if (RollbackTransaction())
532         {
533         printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Failed to rollback transaction'\n");
534         }
535     return -1;
536     }
537
538 tuples = PQntuples(result);
539
540 if (tuples != DIR_NUM)
541     {
542     printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Tariff params count and DIR_NUM does not feet (wanted %d, actually %d)'\n", DIR_NUM, tuples);
543     }
544
545 for (int i = 0; i < std::min(tuples, DIR_NUM); ++i)
546     {
547     int dir;
548
549         {
550         std::stringstream tuple;
551         tuple << PQgetvalue(result, i, 0) << " ";
552         tuple << PQgetvalue(result, i, 1) << " ";
553         tuple << PQgetvalue(result, i, 2) << " ";
554         tuple << PQgetvalue(result, i, 3) << " ";
555         tuple << PQgetvalue(result, i, 4) << " ";
556         tuple << PQgetvalue(result, i, 5) << " ";
557         tuple << PQgetvalue(result, i, 6) << " ";
558         tuple << PQgetvalue(result, i, 7) << " ";
559         tuple << PQgetvalue(result, i, 8) << " ";
560         tuple << PQgetvalue(result, i, 9) << " ";
561
562         tuple >> dir;
563         tuple >> td->dirPrice[dir].priceDayA;
564         td->dirPrice[dir].priceDayA /= 1024 * 1024;
565         tuple >> td->dirPrice[dir].priceDayB;
566         td->dirPrice[dir].priceDayB /= 1024 * 1024;
567         tuple >> td->dirPrice[dir].priceNightA;
568         td->dirPrice[dir].priceNightA /= 1024 * 1024;
569         tuple >> td->dirPrice[dir].priceNightB;
570         td->dirPrice[dir].priceNightB /= 1024 * 1024;
571         tuple >> td->dirPrice[dir].threshold;
572         tuple >> td->dirPrice[dir].hDay;
573         tuple >> td->dirPrice[dir].mDay;
574         tuple >> td->dirPrice[dir].hNight;
575         tuple >> td->dirPrice[dir].mNight;
576         }
577
578     if (std::fabs(td->dirPrice[dir].priceDayA - td->dirPrice[dir].priceNightA) < 1.0e-3 / pt_mega &&
579         std::fabs(td->dirPrice[dir].priceDayB - td->dirPrice[dir].priceNightB) < 1.0e-3 / pt_mega)
580         {
581         td->dirPrice[dir].singlePrice = true;
582         }
583     else
584         {
585         td->dirPrice[dir].singlePrice = false;
586         }
587     if (td->dirPrice[dir].threshold == (int)0xffFFffFF)
588         {
589         td->dirPrice[dir].noDiscount = true;
590         }
591     else
592         {
593
594         td->dirPrice[dir].noDiscount = false;
595         }
596
597     }
598
599 PQclear(result);
600
601 if (CommitTransaction())
602     {
603     printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Failed to commit transaction'\n");
604     return -1;
605     }
606
607 return 0;
608 }
609 //-----------------------------------------------------------------------------
610