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