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