Add support of app_id in GetAll method call on statistics interface
[platform/core/connectivity/stc-manager.git] / src / database / tables / table-statistics.c
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /**
18  * This file implements statistics entity handler methods.
19  *
20  * @file        table-statistics.c
21  */
22
23 #include "stc-db.h"
24 #include "table-statistics.h"
25 #include "db-internal.h"
26
27 /* DELETE statements */
28 #define DELETE_ALL "delete from statistics where time_stamp between ? and ?"
29
30 #define DELETE_APP "delete from statistics where binpath=? and " \
31         "time_stamp between ? and ? "
32
33 #define DELETE_IFACE "delete from statistics where iftype=? and " \
34         "time_stamp between ? and ?"
35
36 #define DELETE_APP_IFACE "delete from statistics where binpath=? and " \
37         "iftype=? and time_stamp between ? and ?"
38
39 #define DELETE_FIRST_BY_NUMBER "delete from statistics where time_stamp in " \
40         "(select time_stamp from statistics desc limit ?)"
41
42 /* SELECT statements */
43 #define SELECT_FOR_PERIOD "select binpath, hw_net_protocol_type, " \
44         "is_roaming, sum(received) as received, " \
45         "sum(sent) as sent, subscriber_id, ground, iftype, ifname from statistics " \
46         "where time_stamp between ? and ? " \
47         "group by binpath, is_roaming, subscriber_id order by received desc"
48
49 #define SELECT_FOR_PERIOD_IFACE "select binpath, hw_net_protocol_type, " \
50         "is_roaming, sum(received) as received, " \
51         "sum(sent) as sent, subscriber_id, ground, iftype, ifname from statistics " \
52         "where time_stamp between ? and ? " \
53         "and iftype=? group by binpath, is_roaming, subscriber_id order by received desc"
54
55 #define SELECT_CHUNKS "select binpath, hw_net_protocol_type, " \
56         "is_roaming, sum(received) as received, " \
57         "sum(sent) as sent, subscriber_id, ground, iftype, ifname, " \
58         "time_stamp - time_stamp % ? as timestamp " \
59         "from statistics where time_stamp between ? and ? " \
60         "group by binpath, timestamp, subscriber_id order by timestamp"
61
62 #define SELECT_CHUNKS_IFACE "select binpath, hw_net_protocol_type, " \
63         "is_roaming, sum(received) as received, " \
64         "sum(sent) as sent, subscriber_id, ground, iftype, ifname, " \
65         "time_stamp - time_stamp % ? as timestamp " \
66         "from statistics where time_stamp between ? and ? and iftype=?" \
67         "group by binpath, timestamp, subscriber_id order by timestamp"
68
69 #define SELECT_APP_DETAILS "select iftype, hw_net_protocol_type, " \
70         "is_roaming, sum(received) as received, sum(sent) as sent, " \
71         "ifname, subscriber_id, ground from statistics " \
72         "where time_stamp between ? and ? and binpath=? " \
73         "group by binpath, iftype, ifname, subscriber_id, hw_net_protocol_type, " \
74         "is_roaming " \
75         "order by time_stamp, binpath, iftype, ifname, subscriber_id, " \
76         "hw_net_protocol_type, is_roaming"
77
78 #define SELECT_APP_DETAILS_IFACE "select iftype, hw_net_protocol_type, " \
79         "is_roaming, sum(received) as received, sum(sent) as sent, " \
80         "ifname, subscriber_id, ground from statistics " \
81         "where time_stamp between ? and ? and binpath=? and iftype=?" \
82         "group by hw_net_protocol_type, is_roaming, iftype, ifname, subscriber_id " \
83         "order by time_stamp, hw_net_protocol_type, is_roaming, iftype, " \
84         "ifname, subscriber_id"
85
86 #define SELECT_CHUNKS_APP "select iftype, hw_net_protocol_type, " \
87         "is_roaming, sum(received) as received, sum(sent) as sent, " \
88         "ifname, subscriber_id, ground, time_stamp - time_stamp % ? as time_stamp " \
89         "from statistics " \
90         "group by iftype, ifname, time_stamp, hw_net_protocol_type, is_roaming  " \
91         "order by time_stamp, iftype, ifname, hw_net_protocol_type, is_roaming"
92
93 #define SELECT_CHUNKS_APP_IFACE "select iftype, hw_net_protocol_type, " \
94         "is_roaming, sum(received) as received, sum(sent) as sent, " \
95         "ifname, subscriber_id, ground, time_stamp - time_stamp % ? as time_stamp " \
96         "from statistics where time_stamp between ? and ? and binpath = ? " \
97         "and iftype = ? " \
98         "group by time_stamp, hw_net_protocol_type, is_roaming, " \
99         "iftype, ifname, subscriber_id " \
100         "order by time_stamp, iftype, ifname, subscriber_id, hw_net_protocol_type, " \
101         "is_roaming"
102
103 #define SELECT_TOTAL "select iftype, hw_net_protocol_type, " \
104         "is_roaming, sum(received) as received, sum(sent) as sent, " \
105         "ifname, subscriber_id, ground from statistics " \
106         "where (time_stamp between ? and ?) " \
107         "and binpath NOT LIKE 'TOTAL_%' " \
108         "group by iftype, ifname, subscriber_id, hw_net_protocol_type, is_roaming " \
109         "order by time_stamp, iftype, ifname, subscriber_id, hw_net_protocol_type, " \
110         "is_roaming"
111
112 #define SELECT_TOTAL_IFACE "select iftype, hw_net_protocol_type, " \
113         "is_roaming, sum(received) as received, sum(sent) as sent, " \
114         "ifname, subscriber_id, ground from statistics " \
115         "where (time_stamp between ? and ?) and iftype=? " \
116         "and binpath NOT LIKE 'TOTAL_%' " \
117         "group by hw_net_protocol_type, is_roaming, " \
118         "iftype, ifname, subscriber_id " \
119         "order by time_stamp, iftype, ifname, subscriber_id, hw_net_protocol_type, " \
120         "is_roaming"
121
122 #define SELECT_CHUNKS_TOTAL "select iftype, hw_net_protocol_type, " \
123         "is_roaming, sum(received) as received, sum(sent) as sent, " \
124         "ifname, subscriber_id, ground, time_stamp - time_stamp % ? as time_stamp " \
125         "from statistics where time_stamp between ? and ? " \
126         "and binpath NOT LIKE 'TOTAL_%' " \
127         "group by time_stamp, iftype, ifname, subscriber_id, hw_net_protocol_type, " \
128         "is_roaming " \
129         "order by time_stamp, iftype, ifname, subscriber_id, hw_net_protocol_type, " \
130         "is_roaming"
131
132 #define SELECT_CHUNKS_TOTAL_IFACE "select iftype, hw_net_protocol_type, " \
133         "is_roaming, sum(received) as received, sum(sent) as sent, " \
134         "ifname, subscriber_id, ground, time_stamp - time_stamp % ? as time_stamp " \
135         "from statistics where time_stamp between ? and ? " \
136         "and iftype = ? " \
137         "and binpath NOT LIKE 'TOTAL_%' " \
138         "group by time_stamp, hw_net_protocol_type, is_roaming, iftype, ifname, subscriber_id " \
139         "order by time_stamp, hw_net_protocol_type, is_roaming, iftype, " \
140         "ifname, subscriber_id"
141
142 /* INSERT statement */
143 #define INSERT_VALUES "insert into statistics " \
144         "(binpath, received, sent, time_stamp, " \
145         "iftype, is_roaming, hw_net_protocol_type, " \
146         "ifname, subscriber_id, ground) " \
147         "values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
148
149 static void __finalize_delete(void);
150
151 #define PREPARE_DELETE(stm, query) do {                         \
152         rc = sqlite3_prepare_v2(db, query, -1, &stm, NULL);     \
153         if (rc != SQLITE_OK) {                                  \
154                 stm = NULL;                                     \
155                 __finalize_delete();                            \
156                 STC_LOGE("Failed to prepare \"%s\"query"        \
157                          , query);                              \
158                 return rc;                                      \
159         }                                                       \
160 } while (0)
161
162 static void __finalize_select(void);
163
164 #define PREPARE_SELECT(stm, query) do {                         \
165         rc = sqlite3_prepare_v2(db, query, -1, &stm, NULL);     \
166         if (rc != SQLITE_OK) {                                  \
167                 stm = NULL;                                     \
168                 __finalize_select();                            \
169                 STC_LOGE("Failed to prepare \"%s\"query"        \
170                          , query);                              \
171                 return rc;                                      \
172         }                                                       \
173 } while (0)
174
175 static void __finalize_insert(void);
176
177 #define PREPARE_INSERT(stm, query) do {                         \
178         rc = sqlite3_prepare_v2(db, query, -1, &stm, NULL);     \
179         if (rc != SQLITE_OK) {                                  \
180                 stm = NULL;                                     \
181                 __finalize_insert();                            \
182                 STC_LOGE("Failed to prepare \"%s\"query"        \
183                          , query);                              \
184                 return rc;                                      \
185         }                                                       \
186 } while (0)
187
188 #define FINALIZE(stm) do {                                      \
189         if (stm) {                                              \
190                 sqlite3_finalize(stm);                          \
191                 stm = NULL;                                     \
192         }                                                       \
193 } while (0)
194
195 /* DELETE statements */
196 /* the following array is strictly ordered
197  * to find required statement the following code will be used:
198  * (app ? 1 : 0) | (iftype ? 2 : 0)
199  */
200 static sqlite3_stmt *delete_query[5];
201
202 /* SELECT statements */
203 static sqlite3_stmt *select_for_period;
204 static sqlite3_stmt *select_for_period_iface;
205 static sqlite3_stmt *select_chunks;
206 static sqlite3_stmt *select_chunks_iface;
207 static sqlite3_stmt *select_app_details;
208 static sqlite3_stmt *select_app_details_iface;
209 static sqlite3_stmt *select_chunks_app;
210 static sqlite3_stmt *select_chunks_app_iface;
211 static sqlite3_stmt *select_total;
212 static sqlite3_stmt *select_total_iface;
213 static sqlite3_stmt *select_chunks_total;
214 static sqlite3_stmt *select_chunks_total_iface;
215
216 /* INSERT statements */
217 static sqlite3_stmt *update_statistics_query;
218
219 static int __prepare_delete(sqlite3 *db)
220 {
221         __STC_LOG_FUNC_ENTER__;
222         int rc;
223         static int initialized;
224
225         if (initialized) {
226                 __STC_LOG_FUNC_EXIT__; //LCOV_EXCL_LINE
227                 return SQLITE_OK; //LCOV_EXCL_LINE
228         }
229
230         PREPARE_DELETE(delete_query[0], DELETE_ALL);
231         PREPARE_DELETE(delete_query[1], DELETE_APP);
232         PREPARE_DELETE(delete_query[2], DELETE_IFACE);
233         PREPARE_DELETE(delete_query[3], DELETE_APP_IFACE);
234         PREPARE_DELETE(delete_query[4], DELETE_FIRST_BY_NUMBER);
235
236         initialized = 1;
237         __STC_LOG_FUNC_EXIT__;
238         return rc;
239 }
240
241 static void __finalize_delete(void)
242 {
243         __STC_LOG_FUNC_ENTER__;
244
245         unsigned int i;
246         for (i = 0; i < sizeof(delete_query) / sizeof(*delete_query); i++)
247                 FINALIZE(delete_query[i]);
248
249         __STC_LOG_FUNC_EXIT__;
250 }
251
252 static int __prepare_select(sqlite3 *db)
253 {
254         __STC_LOG_FUNC_ENTER__;
255         int rc;
256         static int initialized;
257
258         if (initialized) {
259                 __STC_LOG_FUNC_EXIT__; //LCOV_EXCL_LINE
260                 return SQLITE_OK; //LCOV_EXCL_LINE
261         }
262
263         PREPARE_SELECT(select_for_period, SELECT_FOR_PERIOD);
264         PREPARE_SELECT(select_for_period_iface, SELECT_FOR_PERIOD_IFACE);
265         PREPARE_SELECT(select_chunks, SELECT_CHUNKS);
266         PREPARE_SELECT(select_chunks_iface, SELECT_CHUNKS_IFACE);
267         PREPARE_SELECT(select_app_details, SELECT_APP_DETAILS);
268         PREPARE_SELECT(select_app_details_iface, SELECT_APP_DETAILS_IFACE);
269         PREPARE_SELECT(select_chunks_app, SELECT_CHUNKS_APP);
270         PREPARE_SELECT(select_chunks_app_iface, SELECT_CHUNKS_APP_IFACE);
271         PREPARE_SELECT(select_total, SELECT_TOTAL);
272         PREPARE_SELECT(select_total_iface, SELECT_TOTAL_IFACE);
273         PREPARE_SELECT(select_chunks_total, SELECT_CHUNKS_TOTAL);
274         PREPARE_SELECT(select_chunks_total_iface, SELECT_CHUNKS_TOTAL_IFACE);
275
276         initialized = 1;
277         __STC_LOG_FUNC_EXIT__;
278         return rc;
279 }
280
281 static void __finalize_select(void)
282 {
283         __STC_LOG_FUNC_ENTER__;
284
285         FINALIZE(select_for_period);
286         FINALIZE(select_for_period_iface);
287         FINALIZE(select_chunks);
288         FINALIZE(select_chunks_iface);
289         FINALIZE(select_app_details);
290         FINALIZE(select_app_details_iface);
291         FINALIZE(select_chunks_app);
292         FINALIZE(select_chunks_app_iface);
293         FINALIZE(select_total);
294         FINALIZE(select_total_iface);
295         FINALIZE(select_chunks_total);
296         FINALIZE(select_chunks_total_iface);
297
298         __STC_LOG_FUNC_EXIT__;
299 }
300
301 static int __prepare_insert(sqlite3 *db)
302 {
303         __STC_LOG_FUNC_ENTER__;
304         int rc;
305         static int initialized;
306
307         if (initialized) {
308                 __STC_LOG_FUNC_EXIT__; //LCOV_EXCL_LINE
309                 return SQLITE_OK; //LCOV_EXCL_LINE
310         }
311
312         PREPARE_INSERT(update_statistics_query, INSERT_VALUES);
313
314         initialized = 1;
315         __STC_LOG_FUNC_EXIT__;
316         return rc;
317 }
318
319 static void __finalize_insert(void)
320 {
321         __STC_LOG_FUNC_ENTER__;
322
323         FINALIZE(update_statistics_query);
324
325         __STC_LOG_FUNC_EXIT__;
326 }
327
328 static int __is_iftype_defined(const stc_iface_type_e iftype)
329 {
330         return iftype < STC_IFACE_LAST_ELEM &&
331                 iftype > STC_IFACE_UNKNOWN &&
332                 iftype != STC_IFACE_ALL;
333 }
334
335 /* the following array is strictly ordered
336  * to find required statement the following code will be used:
337  * (iface ? 1 : 0) | (total ? 2 : 0) | (chunks ? 4 : 0)
338  */
339 static sqlite3_stmt **details_stms[] = {
340         &select_app_details,
341         &select_app_details_iface,
342         &select_total,
343         &select_total_iface,
344         &select_chunks_app,
345         &select_chunks_app_iface,
346         &select_chunks_total,
347         &select_chunks_total_iface
348 };
349
350 static sqlite3_stmt *__select_statement(const char *app_id,
351                                         const table_statistics_select_rule *rule)
352 {
353         const int stm_index = __is_iftype_defined(rule->iftype) |
354                 ((strlen(app_id) > 0) ? 0 : 2) | (rule->granularity ? 4 : 0);
355         STC_LOGD("stm index %d", stm_index);
356         return *details_stms[stm_index];
357 }
358
359 //LCOV_EXCL_START
360 stc_error_e table_statistics_reset_first_n_entries(int num)
361 {
362         __STC_LOG_FUNC_ENTER__;
363         stc_error_e error_code = STC_ERROR_NONE;
364
365         if (!num) {
366                 STC_LOGE("Invalid number of entries");
367                 return STC_ERROR_INVALID_PARAMETER;
368         }
369
370         DB_ACTION(sqlite3_bind_int(delete_query[4], 1, num));
371
372         if (sqlite3_step(delete_query[4]) != SQLITE_DONE) {
373                 STC_LOGE("Failed to drop collected statistics.");
374                 error_code = STC_ERROR_DB_FAILED;
375                 __STC_LOG_FUNC_EXIT__;
376         }
377 handle_error:
378         if (sqlite3_reset(delete_query[4]) != SQLITE_OK)
379                 error_code = STC_ERROR_DB_FAILED;
380
381         return error_code;
382 }
383 //LCOV_EXCL_STOP
384
385 stc_error_e table_statistics_reset(const table_statistics_reset_rule *rule)
386 {
387         __STC_LOG_FUNC_ENTER__;
388         sqlite3_stmt *stmt;
389         stc_error_e error_code = STC_ERROR_NONE;
390         int pos = 1; /* running through positions where to
391                        bind parameters in the query */
392
393         if (!rule || !rule->interval) {
394                 __STC_LOG_FUNC_EXIT__; //LCOV_EXCL_LINE
395                 return STC_ERROR_INVALID_PARAMETER; //LCOV_EXCL_LINE
396         }
397
398         /* pick a statement depending on parameters.
399            See comment for delete_query */
400         stmt = delete_query[(rule->app_id ? 1 : 0) |
401                 (rule->iftype != STC_IFACE_UNKNOWN &&
402                 rule->iftype != STC_IFACE_LAST_ELEM ? 2 : 0)];
403
404         if (rule->app_id)
405                 DB_ACTION(sqlite3_bind_text(stmt, pos++, rule->app_id, -1,
406                                             SQLITE_TRANSIENT));
407
408         if (rule->iftype != STC_IFACE_LAST_ELEM &&
409                 rule->iftype != STC_IFACE_UNKNOWN)
410                 DB_ACTION(sqlite3_bind_int(stmt, pos++, rule->iftype));
411
412         DB_ACTION(sqlite3_bind_int64(stmt, pos++, rule->interval->from));
413         DB_ACTION(sqlite3_bind_int64(stmt, pos++, rule->interval->to));
414
415         if (sqlite3_step(stmt) != SQLITE_DONE) {
416                 STC_LOGE("Failed to drop collected statistics."); //LCOV_EXCL_LINE
417                 error_code = STC_ERROR_DB_FAILED; //LCOV_EXCL_LINE
418                 __STC_LOG_FUNC_EXIT__; //LCOV_EXCL_LINE
419                 goto handle_error; //LCOV_EXCL_LINE
420         }
421
422         STC_LOGD("Entry deleted successfully.");
423 handle_error:
424         if (sqlite3_reset(stmt) != SQLITE_OK)
425                 error_code = STC_ERROR_DB_FAILED;
426
427         return error_code;
428 }
429
430 stc_error_e table_statistics_foreach_app(const table_statistics_select_rule *rule,
431                                          table_statistics_info_cb info_cb,
432                                          void *user_data)
433 {
434         __STC_LOG_FUNC_ENTER__;
435         table_statistics_info data;
436         sqlite3_stmt *stmt;
437         stc_error_e error_code = STC_ERROR_NONE;
438         int rc;
439         int pos = 1;/* running through positions where to
440                        bind parameters in the query */
441         stc_db_tm_interval_s interval;
442
443         if (!rule || !info_cb) {
444                 __STC_LOG_FUNC_EXIT__; //LCOV_EXCL_LINE
445                 return STC_ERROR_INVALID_PARAMETER; //LCOV_EXCL_LINE
446         }
447
448         memset(&data, 0, sizeof(data));
449
450         if (rule->app_id) {
451                 int ret = table_statistics_per_app(rule->app_id, rule, info_cb, user_data);
452                 __STC_LOG_FUNC_EXIT__;
453                 return ret;
454         }
455
456         /* pick a statement depending on parameters */
457         if (rule->granularity) {
458                 stmt = __is_iftype_defined(rule->iftype) ?
459                         select_chunks_iface : select_chunks;
460
461                 DB_ACTION(sqlite3_bind_int64(stmt, pos++, rule->granularity));
462                 data.interval = &interval;
463         } else {
464                 stmt = __is_iftype_defined(rule->iftype)
465                         ? select_for_period_iface : select_for_period;
466         }
467
468         DB_ACTION(sqlite3_bind_int64(stmt, pos++, rule->from));
469         DB_ACTION(sqlite3_bind_int64(stmt, pos++, rule->to));
470
471         if (__is_iftype_defined(rule->iftype)) {
472                 data.iftype = rule->iftype;
473                 DB_ACTION(sqlite3_bind_int(stmt, pos++, rule->iftype));
474         }
475
476         do {
477                 rc = sqlite3_step(stmt);
478                 switch (rc) {
479                 case SQLITE_ROW:
480                         data.app_id = (char *)sqlite3_column_text(stmt, 0);
481                         data.hw_net_protocol_type = sqlite3_column_int(stmt, 1);
482                         data.roaming = sqlite3_column_int(stmt, 2);
483                         data.cnt.in_bytes = sqlite3_column_int64(stmt, 3);
484                         data.cnt.out_bytes = sqlite3_column_int64(stmt, 4);
485                         data.subscriber_id = (char *)sqlite3_column_text(stmt, 5);
486                         data.ground = sqlite3_column_int(stmt, 6);
487                         data.iftype = sqlite3_column_int(stmt, 7);
488                         data.ifname = (char *)sqlite3_column_text(stmt, 8);
489
490                         if (rule->granularity) {
491                                 interval.from = sqlite3_column_int64(stmt, 9);
492                                 interval.to = interval.from + rule->granularity;
493                         }
494
495                         if (info_cb(&data, user_data) == STC_CANCEL)
496                                 rc = SQLITE_DONE; //LCOV_EXCL_LINE
497                         break;
498                 case SQLITE_DONE:
499                         break;
500                 case SQLITE_ERROR:
501                 default:
502                         error_code = STC_ERROR_DB_FAILED; //LCOV_EXCL_LINE
503                         break; //LCOV_EXCL_LINE
504                 }
505         } while (rc == SQLITE_ROW);
506
507 handle_error:
508         rc = sqlite3_reset(stmt);
509         if (rc != SQLITE_OK)
510                 error_code = STC_ERROR_DB_FAILED;
511
512         __STC_LOG_FUNC_EXIT__;
513         return error_code;
514 }
515
516 API stc_error_e table_statistics_per_app(const char *app_id,
517                                      const table_statistics_select_rule *rule,
518                                      table_statistics_info_cb info_cb,
519                                      void *user_data)
520 {
521         __STC_LOG_FUNC_ENTER__;
522         table_statistics_info data;
523         sqlite3_stmt *stmt;
524         stc_error_e error_code = STC_ERROR_NONE;
525         int rc;
526         int pos = 1; /* running through positions
527                        where to bind parameters in the query */
528         stc_db_tm_interval_s interval;
529
530         memset(&data, 0, sizeof(data));
531
532         if (!rule || !info_cb) {
533                 __STC_LOG_FUNC_EXIT__; //LCOV_EXCL_LINE
534                 return STC_ERROR_INVALID_PARAMETER; //LCOV_EXCL_LINE
535         }
536
537         /* pick a statement depending on parameters.
538            See comment for details_stms */
539         stmt = __select_statement(app_id, rule);
540
541         if (rule->granularity) {
542                 DB_ACTION(sqlite3_bind_int64(stmt, pos++, rule->granularity));
543                 data.interval = &interval;
544         }
545
546         DB_ACTION(sqlite3_bind_int64(stmt, pos++, rule->from));
547         DB_ACTION(sqlite3_bind_int64(stmt, pos++, rule->to));
548
549         if (strlen(app_id) > 0) {
550                 DB_ACTION(sqlite3_bind_text(stmt, pos++, app_id, -1,
551                                             SQLITE_TRANSIENT));
552                 data.app_id = (char *)app_id;
553         }
554
555         if (__is_iftype_defined(rule->iftype))
556                 DB_ACTION(sqlite3_bind_int(stmt, pos++, rule->iftype));
557
558         do {
559                 rc = sqlite3_step(stmt);
560                 switch (rc) {
561                 case SQLITE_ROW:
562                         data.iftype = sqlite3_column_int(stmt, 0);
563                         data.hw_net_protocol_type = sqlite3_column_int(stmt, 1);
564                         data.roaming = sqlite3_column_int(stmt, 2);
565                         data.cnt.in_bytes = sqlite3_column_int64(stmt, 3);
566                         data.cnt.out_bytes = sqlite3_column_int64(stmt, 4);
567                         data.ifname = (char *)sqlite3_column_text(stmt, 5);
568                         data.subscriber_id = (char *)sqlite3_column_text(stmt, 6);
569                         data.ground = sqlite3_column_int(stmt, 7);
570
571                         if (rule->granularity) {
572                                 interval.from = sqlite3_column_int64(stmt, 8);
573                                 interval.to = interval.from + rule->granularity;
574                         }
575
576                         if (info_cb(&data, user_data) == STC_CANCEL)
577                                 rc = SQLITE_DONE; //LCOV_EXCL_LINE
578                         break;
579                 case SQLITE_DONE:
580                         break;
581                 case SQLITE_ERROR:
582                 default:
583                         error_code = STC_ERROR_DB_FAILED; //LCOV_EXCL_LINE
584                         break; //LCOV_EXCL_LINE
585                 }
586         } while (rc == SQLITE_ROW);
587
588 handle_error:
589         rc = sqlite3_reset(stmt);
590         if (rc != SQLITE_OK)
591                 error_code = STC_ERROR_DB_FAILED;
592
593         __STC_LOG_FUNC_EXIT__;
594         return error_code;
595 }
596
597 API stc_error_e table_statistics_insert(stc_db_classid_iftype_key *stat_key,
598                                     stc_db_app_stats *stat,
599                                     time_t last_touch_time)
600 {
601         stc_error_e error_code = STC_ERROR_NONE;
602         sqlite3_stmt *stmt = update_statistics_query;
603         stc_hw_net_protocol_type_e hw_net_protocol_type = STC_PROTOCOL_UNKNOWN;
604         long long int rcv;
605         long long int snd;
606
607         if (!stat->rcv_count && !stat->snd_count) {
608                 error_code = STC_ERROR_INVALID_PARAMETER;
609                 goto handle_error;
610         }
611
612         DB_ACTION(sqlite3_bind_text(stmt, 1, stat->app_id, -1,
613                                     SQLITE_STATIC));
614         DB_ACTION(sqlite3_bind_int(stmt, 2, stat->rcv_count));
615         DB_ACTION(sqlite3_bind_int(stmt, 3, stat->snd_count));
616         DB_ACTION(sqlite3_bind_int64(stmt, 4, (sqlite3_int64)last_touch_time));
617         DB_ACTION(sqlite3_bind_int(stmt, 5, (int)(stat_key->iftype)));
618         DB_ACTION(sqlite3_bind_int(stmt, 6, (int)(stat->is_roaming)));
619         DB_ACTION(sqlite3_bind_int(stmt, 7, (int)hw_net_protocol_type));
620         DB_ACTION(sqlite3_bind_text(stmt, 8, stat_key->ifname ? stat_key->ifname : "",
621                                         -1, SQLITE_STATIC));
622         DB_ACTION(sqlite3_bind_text(stmt, 9,
623                                     stat_key->subscriber_id ? stat_key->subscriber_id : "" ,
624                                     -1, SQLITE_STATIC));
625         DB_ACTION(sqlite3_bind_int(stmt, 10, (int)stat->ground));
626
627         /*we want to reuse tree*/
628         rcv = stat->rcv_count;
629         snd = stat->snd_count;
630         stat->rcv_count = 0;
631         stat->snd_count = 0;
632         if (sqlite3_step(stmt) != SQLITE_DONE) {
633                 STC_LOGE("Failed to record appstat. %s", //LCOV_EXCL_LINE
634                          sqlite3_errmsg(stc_db_get_database()));
635                 error_code = STC_ERROR_DB_FAILED; //LCOV_EXCL_LINE
636                 __STC_LOG_FUNC_EXIT__; //LCOV_EXCL_LINE
637                 goto handle_error; //LCOV_EXCL_LINE
638         }
639
640         if (STC_STAT_LOG)
641                 STC_LOGD("App stat recorded [\033[0;34m%s\033[0;m] "
642                         "rcv[%lld] snd[%lld]", stat->app_id, rcv, snd);
643
644 handle_error:
645         if (sqlite3_reset(stmt) != SQLITE_OK)
646                 error_code = STC_ERROR_DB_FAILED;
647
648         return error_code;
649 }
650
651 /**
652  * This function will be somewhere consumer and will not be placed in this file.
653  */
654 #if 0
655 stc_error_e table_statistics_store_result(app_stat_tree *stats)
656 {
657         time_t current_time;
658
659         pthread_rwlock_rdlock(&stats->guard);
660         WALK_TREE(stats->tree, print_appstat);
661         pthread_rwlock_unlock(&stats->guard);
662
663         time(&current_time);
664         stats->last_touch_time = current_time;
665
666         /* it's reader only, we don't modify tree, don't reduce it,
667          *              due we want to reuse it in next iteration */
668         pthread_rwlock_rdlock(&stats->guard);
669         g_tree_foreach((GTree *) stats->tree, __store_application_stat,
670                        &stats->last_touch_time);
671
672         pthread_rwlock_unlock(&stats->guard);
673         flush_quota_table();
674         change_db_entries_num_num(g_tree_nnodes((GTree *)stats->tree));
675
676         return STC_ERROR_NONE;
677 }
678 #endif
679
680 stc_error_e table_statistics_prepare(sqlite3 *db)
681 {
682         __STC_LOG_FUNC_ENTER__;
683
684         stc_error_e error_code = STC_ERROR_NONE;
685
686         if (db == NULL) {
687                 __STC_LOG_FUNC_EXIT__; //LCOV_EXCL_LINE
688                 return STC_ERROR_DB_FAILED; //LCOV_EXCL_LINE
689         }
690
691         DB_ACTION(__prepare_delete(db));
692         DB_ACTION(__prepare_select(db));
693         DB_ACTION(__prepare_insert(db));
694
695 handle_error:
696
697         __STC_LOG_FUNC_EXIT__;
698         return error_code;
699 }
700
701 void table_statistics_finalize(void)
702 {
703         __STC_LOG_FUNC_ENTER__;
704         __finalize_delete();
705         __finalize_select();
706         __finalize_insert();
707         __STC_LOG_FUNC_EXIT__;
708 }