]> git.stg.codes - stg.git/blob - projects/stargazer/plugins/store/postgresql/postgresql_store_tariffs.cpp
Ticket 37. The changePolicyTimeout field added to the CREATE TABLE
[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     if (version > 7)
321         query << ", change_policy = '" << TARIFF::ChangePolicyToString(td.tariffConf.changePolicy) << "', \
322                   change_policy_timeout = CAST('" << Int2TS(td.tariffConf.changePolicyTimeout) << "' AS TIMESTAMP)";
323
324     query << " WHERE pk_tariff = " << id;
325
326     result = PQexec(connection, query.str().c_str());
327     }
328
329 if (PQresultStatus(result) != PGRES_COMMAND_OK)
330     {
331     strError = PQresultErrorMessage(result);
332     PQclear(result);
333     printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): '%s'\n", strError.c_str());
334     if (RollbackTransaction())
335         {
336         printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): 'Failed to rollback transaction'\n");
337         }
338     return -1;
339     }
340
341 PQclear(result);
342
343 for(int i = 0; i < DIR_NUM; i++)
344     {
345     double pda = td.dirPrice[i].priceDayA * 1024 * 1024;
346     double pdb = td.dirPrice[i].priceDayB * 1024 * 1024;
347     double pna = 0;
348     double pnb = 0;
349
350     if (td.dirPrice[i].singlePrice)
351         {
352         pna = pda;
353         pnb = pdb;
354         }
355     else
356         {
357         pna = td.dirPrice[i].priceNightA * 1024 * 1024;
358         pnb = td.dirPrice[i].priceNightB * 1024 * 1024;
359         }
360
361     int threshold = 0;
362     if (td.dirPrice[i].noDiscount)
363         {
364         threshold = 0xffFFffFF;
365         }
366     else
367         {
368         threshold = td.dirPrice[i].threshold;
369         }
370
371         {
372         std::ostringstream query;
373         query << "UPDATE tb_tariffs_params SET \
374                       price_day_a = " << pda << ", \
375                       price_day_b = " << pdb << ", \
376                       price_night_a = " << pna << ", \
377                       price_night_b = " << pnb << ", \
378                       threshold = " << threshold << ", \
379                       time_day_begins = CAST('" << td.dirPrice[i].hDay
380                                                 << ":"
381                                                 << td.dirPrice[i].mDay << "' AS TIME), \
382                       time_day_ends = CAST('" << td.dirPrice[i].hNight
383                                               << ":"
384                                               << td.dirPrice[i].mNight << "' AS TIME) \
385                  WHERE fk_tariff = " << id << " AND dir_num = " << i;
386
387         result = PQexec(connection, query.str().c_str());
388         }
389
390     if (PQresultStatus(result) != PGRES_COMMAND_OK)
391         {
392         strError = PQresultErrorMessage(result);
393         PQclear(result);
394         printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): '%s'\n", strError.c_str());
395         if (RollbackTransaction())
396             {
397             printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): 'Failed to rollback transaction'\n");
398             }
399         return -1;
400         }
401
402     PQclear(result);
403     }
404
405 if (CommitTransaction())
406     {
407     printfd(__FILE__, "POSTGRESQL_STORE::SaveTariff(): 'Failed to commit transaction'\n");
408     return -1;
409     }
410
411 return 0;
412 }
413 //-----------------------------------------------------------------------------
414 int POSTGRESQL_STORE::RestoreTariff(TARIFF_DATA * td,
415                                   const std::string & tariffName) const
416 {
417 STG_LOCKER lock(&mutex);
418
419 if (PQstatus(connection) != CONNECTION_OK)
420     {
421     printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Connection lost. Trying to reconnect...'\n", strError.c_str());
422     if (Reset())
423         {
424         strError = "Connection lost";
425         printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): '%s'\n", strError.c_str());
426         return -1;
427         }
428     }
429
430 PGresult * result;
431
432 if (StartTransaction())
433     {
434     printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Failed to start transaction'\n");
435     return -1;
436     }
437
438 std::string ename = tariffName;
439
440 if (EscapeString(ename))
441     {
442     printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Failed to escape name'\n");
443     if (RollbackTransaction())
444         {
445         printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Failed to rollback transaction'\n");
446         }
447     return -1;
448     }
449
450 td->tariffConf.name = tariffName;
451
452 std::ostringstream query;
453 query << "SELECT pk_tariff, \
454                  fee, \
455                  free, \
456                  passive_cost, \
457                  traff_type";
458
459 if (version > 6)
460     query << ", period";
461
462 if (version > 7)
463     query << ", change_policy \
464               , change_policy_timeout";
465
466 query << " FROM tb_tariffs WHERE name = '" << ename << "'";
467
468 result = PQexec(connection, query.str().c_str());
469
470 if (PQresultStatus(result) != PGRES_TUPLES_OK)
471     {
472     strError = PQresultErrorMessage(result);
473     PQclear(result);
474     printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): '%s'\n", strError.c_str());
475     if (RollbackTransaction())
476         {
477         printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Failed to rollback transaction'\n");
478         }
479     return -1;
480     }
481
482 int tuples = PQntuples(result);
483
484 if (tuples != 1)
485     {
486     strError = "Failed to fetch tariff data";
487     printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Invalid number of tuples. Wanted 1, actulally %d'\n", tuples);
488     PQclear(result);
489     if (RollbackTransaction())
490         {
491         printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Failed to rollback transaction'\n");
492         }
493     return -1;
494     }
495
496 int id;
497
498     {
499     std::stringstream tuple;
500     tuple << PQgetvalue(result, 0, 0) << " ";
501     tuple << PQgetvalue(result, 0, 1) << " ";
502     tuple << PQgetvalue(result, 0, 2) << " ";
503     tuple << PQgetvalue(result, 0, 3) << " ";
504     tuple << PQgetvalue(result, 0, 4) << " ";
505
506     tuple >> id;
507     tuple >> td->tariffConf.fee;
508     tuple >> td->tariffConf.free;
509     tuple >> td->tariffConf.passiveCost;
510     tuple >> td->tariffConf.traffType;
511     }
512
513 if (version > 6)
514     td->tariffConf.period = TARIFF::StringToPeriod(PQgetvalue(result, 0, 5));
515
516 if (version > 7)
517     {
518     td->tariffConf.changePolicy = TARIFF::StringToChangePolicy(PQgetvalue(result, 0, 6));
519     td->tariffConf.changePolicyTimeout = TS2Int(PQgetvalue(result, 0, 7));
520     }
521
522 PQclear(result);
523
524 query.str("");
525 query << "SELECT dir_num, \
526                  price_day_a, \
527                  price_day_b, \
528                  price_night_a, \
529                  price_night_b, \
530                  threshold, \
531                  EXTRACT(hour FROM time_day_begins), \
532                  EXTRACT(minute FROM time_day_begins), \
533                  EXTRACT(hour FROM time_day_ends), \
534                  EXTRACT(minute FROM time_day_ends) \
535           FROM tb_tariffs_params \
536           WHERE fk_tariff = " << id;
537
538 result = PQexec(connection, query.str().c_str());
539
540 if (PQresultStatus(result) != PGRES_TUPLES_OK)
541     {
542     strError = PQresultErrorMessage(result);
543     PQclear(result);
544     printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): '%s'\n", strError.c_str());
545     if (RollbackTransaction())
546         {
547         printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Failed to rollback transaction'\n");
548         }
549     return -1;
550     }
551
552 tuples = PQntuples(result);
553
554 if (tuples != DIR_NUM)
555     {
556     printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Tariff params count and DIR_NUM does not feet (wanted %d, actually %d)'\n", DIR_NUM, tuples);
557     }
558
559 for (int i = 0; i < std::min(tuples, DIR_NUM); ++i)
560     {
561     int dir;
562
563         {
564         std::stringstream tuple;
565         tuple << PQgetvalue(result, i, 0) << " ";
566         tuple << PQgetvalue(result, i, 1) << " ";
567         tuple << PQgetvalue(result, i, 2) << " ";
568         tuple << PQgetvalue(result, i, 3) << " ";
569         tuple << PQgetvalue(result, i, 4) << " ";
570         tuple << PQgetvalue(result, i, 5) << " ";
571         tuple << PQgetvalue(result, i, 6) << " ";
572         tuple << PQgetvalue(result, i, 7) << " ";
573         tuple << PQgetvalue(result, i, 8) << " ";
574         tuple << PQgetvalue(result, i, 9) << " ";
575
576         tuple >> dir;
577         tuple >> td->dirPrice[dir].priceDayA;
578         td->dirPrice[dir].priceDayA /= 1024 * 1024;
579         tuple >> td->dirPrice[dir].priceDayB;
580         td->dirPrice[dir].priceDayB /= 1024 * 1024;
581         tuple >> td->dirPrice[dir].priceNightA;
582         td->dirPrice[dir].priceNightA /= 1024 * 1024;
583         tuple >> td->dirPrice[dir].priceNightB;
584         td->dirPrice[dir].priceNightB /= 1024 * 1024;
585         tuple >> td->dirPrice[dir].threshold;
586         tuple >> td->dirPrice[dir].hDay;
587         tuple >> td->dirPrice[dir].mDay;
588         tuple >> td->dirPrice[dir].hNight;
589         tuple >> td->dirPrice[dir].mNight;
590         }
591
592     if (std::fabs(td->dirPrice[dir].priceDayA - td->dirPrice[dir].priceNightA) < 1.0e-3 / pt_mega &&
593         std::fabs(td->dirPrice[dir].priceDayB - td->dirPrice[dir].priceNightB) < 1.0e-3 / pt_mega)
594         {
595         td->dirPrice[dir].singlePrice = true;
596         }
597     else
598         {
599         td->dirPrice[dir].singlePrice = false;
600         }
601     if (td->dirPrice[dir].threshold == (int)0xffFFffFF)
602         {
603         td->dirPrice[dir].noDiscount = true;
604         }
605     else
606         {
607
608         td->dirPrice[dir].noDiscount = false;
609         }
610
611     }
612
613 PQclear(result);
614
615 if (CommitTransaction())
616     {
617     printfd(__FILE__, "POSTGRESQL_STORE::RestoreTariff(): 'Failed to commit transaction'\n");
618     return -1;
619     }
620
621 return 0;
622 }
623 //-----------------------------------------------------------------------------
624