5af22a0da48a1ff69ed3baffcc8de86365aa00dc
[platform/core/telephony/tel-plugin-database.git] / src / database_main.c
1 /*
2  * tel-plugin-database
3  *
4  * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: DongHoo Park <donghoo.park@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <strings.h>
26
27 #include <glib.h>
28 #include <sqlite3.h>
29 #include <unistd.h>
30
31 #include <tcore.h>
32 #include <server.h>
33 #include <plugin.h>
34 #include <storage.h>
35
36 #ifndef PLUGIN_VERSION
37 #define PLUGIN_VERSION 1
38 #endif
39
40 #define BUSY_WAITING_USEC 50000 /* 0.05 sec */
41 #define BUSY_WAITING_MAX 20 /* wait for max 1 sec */
42
43
44 static gboolean __update_query_database(Storage *strg, void *handle, const char *query, GHashTable *in_param)
45 {
46         int rv = 0;
47         sqlite3_stmt *stmt = NULL;
48         char szQuery[1000+1];   /* +1 is for NULL Termination Character '\0' */
49
50         GHashTableIter iter;
51         gpointer key, value;
52
53         dbg("update query");
54
55         memset(szQuery, '\0', 1001);
56         strncpy(szQuery, query, 1000);
57
58         rv = sqlite3_prepare_v2(handle, szQuery, strlen(szQuery), &stmt, NULL);
59         if (rv != SQLITE_OK) {
60                 err("fail to connect to table (%d)", rv);
61                 return FALSE;
62         }
63
64         if (in_param) {
65                 g_hash_table_iter_init(&iter, in_param);
66                 while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
67                         dbg("key(%s), value(%s)", (const char *)key, (const char *)value);
68
69                         if (!value || g_strcmp0((const char *)value, "") == 0) {
70                                 dbg("bind null");
71                                 rv = sqlite3_bind_null(stmt, atoi((const char *)key));
72                         } else {
73                                 dbg("bind value");
74                                 rv = sqlite3_bind_text(stmt, atoi((const char *)key), (const char *)value, strlen((const char *)value),
75                                                 SQLITE_STATIC);
76                         }
77
78                         if (rv != SQLITE_OK) {
79                                 dbg("fail to bind data (%d)", rv);
80                                 break;
81                         }
82                 }
83         }
84
85         if (rv != SQLITE_OK) {
86                 sqlite3_finalize(stmt);
87                 return FALSE;
88         }
89
90         rv = sqlite3_step(stmt);
91         dbg("update query executed (%d)", rv);
92         sqlite3_finalize(stmt);
93
94         if (rv != SQLITE_DONE)
95                 return FALSE;
96
97         return TRUE;
98 }
99
100 static int _busy_handler(void *pData, int count)
101 {
102          if (count < BUSY_WAITING_MAX) {
103                 usleep(BUSY_WAITING_USEC);
104                 return 1;
105         }
106
107         dbg("Busy Handler will be returned SQLITE_BUSY error\n");
108         return 0;
109 }
110
111 static void *create_handle(Storage *strg, const char *path)
112 {
113         int rv = 0;
114         sqlite3 *handle = NULL;
115
116         if (path == NULL) {
117                 err("Invalid input param error");
118                 return NULL;
119         }
120
121         rv = sqlite3_open(path, &handle);
122         if (rv != SQLITE_OK) {
123                 err("fail to connect database err(%d), errmsg(%s)", rv, sqlite3_errmsg(handle));
124                 return NULL;
125         }
126
127         rv = sqlite3_busy_handler(handle, _busy_handler, NULL);
128         if (rv != SQLITE_OK) {
129                 err("fail to register busy handler err(%d), errmsg(%s)", rv, sqlite3_errmsg(handle));
130                 return NULL;
131         }
132
133         dbg("connected to %s", path);
134         return handle;
135 }
136
137 static gboolean remove_handle(Storage *strg, void *handle)
138 {
139         int rv = 0;
140
141         if (!handle)
142                 return FALSE;
143
144         rv = sqlite3_close(handle);
145         if (rv != SQLITE_OK) {
146                 err("fail to close database err(%d)", rv);
147                 handle = NULL;
148                 return FALSE;
149         }
150
151         dbg("disconnected from database");
152         return TRUE;
153 }
154
155 static gboolean update_query_database(Storage *strg, void *handle, const char *query, GHashTable *in_param)
156 {
157         gboolean ret = TRUE;
158
159         dbg("update query");
160
161         ret = __update_query_database(strg, handle, query, in_param);
162
163         return ret;
164 }
165
166 static gboolean _read_query_database_internal(Storage *strg, void *handle, const char *query, GHashTable *in_param,
167                 gpointer out_param, int out_param_cnt, gboolean in_order)
168 {
169         int rv = 0, local_index = 0, outter_index = 0;
170         sqlite3_stmt *stmt = NULL;
171         char szQuery[5000+1];   /* +1 is for NULL Termination Character '\0' */
172
173         GHashTableIter iter;
174         gpointer key, value;
175
176         dbg("read query");
177
178         memset(szQuery, '\0', 5001);
179         strncpy(szQuery, query, 5000);
180
181         rv = sqlite3_prepare_v2(handle, szQuery, strlen(szQuery), &stmt, NULL);
182         if (rv != SQLITE_OK) {
183                 err("fail to connect to table (%d)", rv);
184                 return FALSE;
185         }
186
187         if (in_param) {
188                 g_hash_table_iter_init(&iter, in_param);
189                 while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
190                         dbg("key(%s), value(%s)", (const char *)key, (const char *)value);
191
192                         if (!value || g_strcmp0((const char *)value, "") == 0) {
193                                 dbg("bind null");
194                                 rv = sqlite3_bind_null(stmt, atoi((const char *)key));
195                         } else {
196                                 dbg("bind value");
197                                 rv = sqlite3_bind_text(stmt, atoi((const char *)key), (const char *)value, strlen((const char *)value),
198                                                 SQLITE_STATIC);
199                         }
200
201                         if (rv != SQLITE_OK) {
202                                 dbg("fail to bind data (%d)", rv);
203                                 break;
204                         }
205                 }
206         }
207
208         if (rv != SQLITE_OK) {
209                 sqlite3_finalize(stmt);
210                 return FALSE;
211         }
212
213         rv = sqlite3_step(stmt);
214         dbg("read query executed (%d), in_order (%d)", rv, in_order);
215
216         while (rv == SQLITE_ROW) {
217                 GHashTable *out_param_data;
218
219                 out_param_data = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
220
221                 for (local_index = 0; local_index < out_param_cnt; local_index++) {
222                         char tmp_key[32];
223                         const unsigned char *tmp;
224                         tmp = sqlite3_column_text(stmt, local_index);
225                         snprintf(tmp_key, sizeof(tmp_key), "%d", local_index);
226                         g_hash_table_insert(out_param_data, g_strdup(tmp_key), g_strdup((const char *)tmp));
227                 }
228
229                 if (in_order) {
230                         GSList **temp = out_param;
231                         *temp = g_slist_append(*temp, out_param_data);
232                 } else {
233                         char tmp_key_outter[32];
234                         snprintf(tmp_key_outter, sizeof(tmp_key_outter), "%d", outter_index);
235                         g_hash_table_insert((GHashTable*)out_param, g_strdup(tmp_key_outter), out_param_data);
236                 }
237                 outter_index++;
238                 rv = sqlite3_step(stmt);
239         }
240
241         sqlite3_finalize(stmt);
242         return TRUE;
243 }
244
245 static gboolean read_query_database(Storage *strg, void *handle, const char *query, GHashTable *in_param,
246                 GHashTable **out_param, int out_param_cnt)
247 {
248         GHashTable *out_hash_table;
249
250         if (out_param == NULL)
251                 return FALSE;
252
253         out_hash_table = g_hash_table_new_full(g_str_hash, g_str_equal,
254                         g_free, (GDestroyNotify)g_hash_table_destroy);
255
256         if (_read_query_database_internal(strg,
257                         handle, query, in_param, out_hash_table, out_param_cnt, FALSE) == FALSE) {
258                 g_hash_table_destroy(out_hash_table);
259                 return FALSE;
260         }
261
262         *out_param = out_hash_table;
263
264         return TRUE;
265 }
266
267 static gboolean read_query_database_in_order(Storage *strg, void *handle, const char *query, GHashTable *in_param,
268                 GSList **out_param, int out_param_cnt)
269 {
270         if (_read_query_database_internal(strg,
271                         handle, query, in_param, out_param, out_param_cnt, TRUE) == FALSE)
272                 return FALSE;
273
274         return TRUE;
275 }
276
277 static gboolean insert_query_database(Storage *strg, void *handle, const char *query, GHashTable *in_param)
278 {
279         int rv = 0;
280         sqlite3_stmt *stmt = NULL;
281         char szQuery[5000+1];   /* +1 is for NULL Termination Character '\0' */
282
283         GHashTableIter iter;
284         gpointer key, value;
285         dbg("insert query");
286
287         memset(szQuery, '\0', 5001);
288         strncpy(szQuery, query, 5000);
289
290         rv = sqlite3_prepare_v2(handle, szQuery, strlen(szQuery), &stmt, NULL);
291         if (rv != SQLITE_OK) {
292                 err("fail to connect to table (%d)", rv);
293                 return FALSE;
294         }
295
296         if (in_param) {
297                 g_hash_table_iter_init(&iter, in_param);
298                 while (g_hash_table_iter_next(&iter, &key, &value) == TRUE) {
299                         dbg("key(%s), value(%s)", (const char *)key, (const char *)value);
300
301                         if (!value || g_strcmp0((const char *)value, "") == 0) {
302                                 dbg("bind null");
303                                 rv = sqlite3_bind_null(stmt, atoi((const char *)key));
304                         } else {
305                                 dbg("bind value");
306                                 rv = sqlite3_bind_text(stmt, atoi((const char *)key), (const char *)value, strlen((const char *)value),
307                                                 SQLITE_STATIC);
308                         }
309
310                         if (rv != SQLITE_OK) {
311                                 dbg("fail to bind data (%d)", rv);
312                                 break;
313                         }
314                 }
315         }
316
317         if (rv != SQLITE_OK) {
318                 sqlite3_finalize(stmt);
319                 return FALSE;
320         }
321
322         rv = sqlite3_step(stmt);
323         dbg("insert query executed (%d)", rv);
324         sqlite3_finalize(stmt);
325
326         if (rv != SQLITE_DONE)
327                 return FALSE;
328
329         return TRUE;
330 }
331
332 static gboolean remove_query_database(Storage *strg, void *handle, const char *query, GHashTable *in_param)
333 {
334         gboolean ret = TRUE;
335
336         dbg("remove query");
337
338         ret = __update_query_database(strg, handle, query, in_param);
339
340         return ret;
341 }
342
343 static struct storage_operations ops = {
344         .create_handle = create_handle,
345         .remove_handle = remove_handle,
346         .update_query_database = update_query_database,
347         .read_query_database = read_query_database,
348         .read_query_database_in_order = read_query_database_in_order,
349         .insert_query_database = insert_query_database,
350         .remove_query_database = remove_query_database,
351 };
352
353 static gboolean on_load()
354 {
355         dbg("i'm load!");
356         return TRUE;
357 }
358
359 static gboolean on_init(TcorePlugin *p)
360 {
361         if (!p)
362                 return FALSE;
363
364         tcore_storage_new(p, "database", &ops);
365
366         dbg("finish to initialize database plug-in");
367         return TRUE;
368 }
369
370 static void on_unload(TcorePlugin *p)
371 {
372         Storage *strg;
373
374         if (!p)
375                 return;
376
377         dbg("i'm unload!");
378
379         strg = tcore_server_find_storage(tcore_plugin_ref_server(p), "database");
380         if (!strg)
381                 return;
382
383         tcore_storage_free(strg);
384         return;
385
386 }
387
388 EXPORT_API struct tcore_plugin_define_desc plugin_define_desc = {
389         .name = "DATABASE",
390         .priority = TCORE_PLUGIN_PRIORITY_HIGH - 1,
391         .version = PLUGIN_VERSION,
392         .load = on_load,
393         .init = on_init,
394         .unload = on_unload
395 };