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