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