Release from caller
[platform/core/multimedia/media-server.git] / lib / media-util-db.c
1 /*
2  * Media Utility
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  */
19
20 #include <unistd.h>
21 #include <dlfcn.h>
22
23 #include <unicode/utypes.h>
24 #include <unicode/ucol.h>
25 #include <unicode/uiter.h>
26 #include <unicode/ustring.h>
27 #include <vconf.h>
28
29 #include "media-util-dbg.h"
30 #include "media-util-ipc.h"
31 #include "media-util-db.h"
32 #include "media-util-err.h"
33 #include "media-util-user.h"
34 #ifdef _USE_ON_DEMAND
35 #include "media-util-socket-activation.h"
36 #endif
37
38 static int __media_db_busy_handler(void *pData, int count)
39 {
40         usleep(50000);
41
42         MSAPI_DBG("media_db_busy_handler called : %d", count);
43
44         return 200 - count;
45 }
46
47 /* The collating function must return an integer that is negative, zero or positive */
48 static int __media_db_collate_icu_8(void *ucol, int str1_len, const void *str1, int str2_len, const void *str2)
49 {
50         UCharIterator uiter1, uiter2;
51         UErrorCode error = U_ZERO_ERROR;
52
53         uiter_setUTF8(&uiter1, (const char *) str1, str1_len);
54         uiter_setUTF8(&uiter2, (const char *) str2, str2_len);
55
56         UCollationResult result = ucol_strcollIter((UCollator *) ucol, &uiter1, &uiter2, &error);
57         if (U_FAILURE(error)) {
58                 MSAPI_DBG_ERR("ucol_strcollIter error: %d", error);
59                 return -1;
60         }
61
62         return result;
63 }
64
65 static void __media_db_collation_cb(void* pArg, sqlite3* handle, int charset, const char* name)
66 {
67         int ret = MS_MEDIA_ERR_NONE;
68         UErrorCode status = U_ZERO_ERROR;
69         const char* locale = NULL;
70         char *lang = NULL;
71         UCollator* ucol = NULL;
72
73         if (!handle || !name || strlen(name) == 0) {
74                 MSAPI_DBG_ERR("Input parameter is NULL");
75                 return;
76         }
77
78         if (charset == SQLITE_UTF8 && !sqlite3_stricmp(name, "localized")) {
79                 lang = vconf_get_str(VCONFKEY_LANGSET);
80                 /* get current locale */
81                 if (lang) {
82                         uloc_setDefault(lang, &status);
83                         free(lang);
84                 } else {
85                         MSAPI_DBG_ERR("Fail to get current language vconf");
86                         return;
87                 }
88                 locale = uloc_getDefault();
89                 if (locale == NULL) {
90                         MSAPI_DBG_ERR("Fail to get current locale");
91                         return;
92                 }
93                 MSAPI_DBG_INFO("locale : %s", locale);
94
95                 ucol = ucol_open(locale, &status);
96                 if (status == U_USING_DEFAULT_WARNING) {
97                         MSAPI_DBG("ucol_open success with default collate option");
98                 } else if (U_FAILURE(status)) {
99                         MSAPI_DBG_ERR("ucol_open fail : %d", status);
100                         return;
101                 }
102
103                 ucol_setStrength(ucol, UCOL_SECONDARY); /* NOTICE : MCD sets UCOL_PRIMARY */
104                 if (U_FAILURE(status)) {
105                         MSAPI_DBG_ERR("ucol_setStrength fail : %d", status);
106                         return;
107                 }
108
109                 ret = sqlite3_create_collation_v2(handle, name, SQLITE_UTF8, ucol, __media_db_collate_icu_8, (void *)ucol_close);
110                 if (ret != SQLITE_OK) {
111                         MSAPI_DBG_ERR("sqlite3_create_collation_v2 fail : %d", ret);
112                         ucol_close(ucol);
113                 } else {
114                         MSAPI_DBG("sqlite3_create_collation_v2 success");
115                 }
116         } else {
117                 MSAPI_DBG_ERR("No matching collator for %s", name);
118         }
119 }
120
121 static int __media_db_connect_db_with_handle(sqlite3 **db_handle, uid_t uid, bool need_write)
122 {
123         int ret = SQLITE_OK;
124         char *db_path = NULL;
125         char *sql = NULL;
126         MSAPI_DBG_ERR("need_write[%d]", need_write);
127         ret = ms_user_get_media_db_path(uid, &db_path);
128         MSAPI_RETVM_IF(ret != MS_MEDIA_ERR_NONE, ret, "ms_user_get_media_db_path failed");
129         MSAPI_RETVM_IF(!db_path, MS_MEDIA_ERR_DB_INTERNAL, "db_path is NULL");
130
131         /*Connect DB*/
132         if (need_write)
133                 ret = sqlite3_open_v2(db_path, db_handle, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
134         else
135                 ret = sqlite3_open_v2(db_path, db_handle, SQLITE_OPEN_READONLY, NULL);
136
137         if (SQLITE_OK != ret) {
138                 MSAPI_DBG_ERR("error when db open path[%s],ret[%d]", db_path, ret);
139                 free(db_path);
140                 *db_handle = NULL;
141                 return MS_MEDIA_ERR_DB_INTERNAL;
142         }
143         free(db_path);
144
145         if (*db_handle == NULL) {
146                 MSAPI_DBG_ERR("*db_handle is NULL");
147                 return MS_MEDIA_ERR_DB_INTERNAL;
148         }
149
150         /*Register busy handler*/
151         ret = sqlite3_busy_handler(*db_handle, __media_db_busy_handler, NULL);
152         if (SQLITE_OK != ret) {
153                 if (*db_handle)
154                         MSAPI_DBG_ERR("[error when register busy handler] %s", sqlite3_errmsg(*db_handle));
155
156                 sqlite3_close_v2(*db_handle);
157                 *db_handle = NULL;
158
159                 return MS_MEDIA_ERR_DB_INTERNAL;
160         }
161
162         /*For TV internal space issue, change TRUNCATE to OFF */
163         sql = sqlite3_mprintf("%s", "PRAGMA journal_mode = OFF");
164         ret = sqlite3_exec(*db_handle, sql, NULL, NULL, NULL);
165         sqlite3_free(sql);
166         if (SQLITE_OK != ret) {
167                 if (*db_handle)
168                         MSAPI_DBG_ERR("[error when change the journal mode] %s", sqlite3_errmsg(*db_handle));
169
170                 sqlite3_close_v2(*db_handle);
171                 *db_handle = NULL;
172
173                 if (ret == SQLITE_CORRUPT) {
174                         MSAPI_DBG_ERR("MEDIA DB IS CORRUPTED");
175                         return MS_MEDIA_ERR_DB_CORRUPT;
176                 }
177
178                 return MS_MEDIA_ERR_DB_INTERNAL;
179         }
180
181         /* Set for localized collate */
182         sqlite3_collation_needed(*db_handle, NULL, __media_db_collation_cb);
183         MSAPI_DBG_ERR("Finish");
184         return MS_MEDIA_ERR_NONE;
185 }
186
187 #define RETRY_CNT 9
188 #define SLEEP_TIME 1000 * 1000
189 static int __media_db_update_directly(sqlite3 *db_handle, const char *sql_str)
190 {
191         int ret = MS_MEDIA_ERR_NONE;
192         char *zErrMsg = NULL;
193         int retry_count = 0;
194
195 EXEC_RETRY:
196         ret = sqlite3_exec(db_handle, sql_str, NULL, NULL, &zErrMsg);
197
198         if (SQLITE_OK != ret) {
199                 MSAPI_ERR_SLOG("Error[%s],Query[%s]", zErrMsg, sql_str);
200                 sqlite3_free(zErrMsg);
201                 if (ret == SQLITE_BUSY) {
202                         ret = MS_MEDIA_ERR_DB_BUSY_FAIL;
203                 } else if (ret == SQLITE_CONSTRAINT) {
204                         ret = MS_MEDIA_ERR_DB_CONSTRAINT_FAIL;
205                 } else if (ret == SQLITE_FULL) {
206                         ret = MS_MEDIA_ERR_DB_FULL_FAIL;
207                 } else if (ret == SQLITE_LOCKED) {
208                         if (retry_count < RETRY_CNT) {
209                                 MSAPI_DBG_ERR("Locked retry[%d]", retry_count);
210                                 retry_count++;
211                                 usleep(SLEEP_TIME);
212                                 goto EXEC_RETRY;
213                         }
214                         ret = MS_MEDIA_ERR_DB_INTERNAL;
215                 } else {
216                         ret = MS_MEDIA_ERR_DB_INTERNAL;
217                 }
218         }
219
220         return ret;
221 }
222
223 int media_db_check_integrity(sqlite3 *handle)
224 {
225         MSAPI_RETVM_IF(handle == NULL, MS_MEDIA_ERR_INVALID_PARAMETER, "Handle is NULL");
226
227         int ret = 0;
228         sqlite3_stmt *stmt = NULL;
229         const char integrity_check_query[] = "PRAGMA integrity_check";
230
231         ret = sqlite3_prepare_v2(handle, integrity_check_query, strlen(integrity_check_query), &stmt, NULL);
232         if (ret != SQLITE_OK) {
233                 MSAPI_DBG_ERR("prepare error, ret = %d, error = %s", ret, sqlite3_errmsg(handle));
234                 return MS_MEDIA_ERR_DB_CORRUPT;
235         }
236
237         ret = sqlite3_step(stmt);
238         if (ret != SQLITE_ROW) {
239                 MSAPI_DBG_ERR("integrity_check failed in step");
240                 sqlite3_finalize(stmt);
241                 return MS_MEDIA_ERR_DB_CORRUPT;
242         }
243
244         char* check_result = (char*) sqlite3_column_text(stmt, 0);
245         if (check_result == NULL || strncmp(check_result, "ok", strlen(check_result))) {
246                 MSAPI_DBG_ERR("integrity_check failed - result(%s)\n", check_result);
247                 sqlite3_finalize(stmt);
248                 return MS_MEDIA_ERR_DB_CORRUPT;
249         }
250         sqlite3_finalize(stmt);
251
252         return MS_MEDIA_ERR_NONE;
253 }
254
255 int media_db_connect(sqlite3 **handle, uid_t uid, bool need_write)
256 {
257         int ret = MS_MEDIA_ERR_NONE;
258         sqlite3 * db_handle = NULL;
259         int retry_cnt = 0;
260
261         MSAPI_DBG_FUNC();
262
263 RETRY_CONN:
264         ret = __media_db_connect_db_with_handle(&db_handle, uid, need_write);
265         if (ret != MS_MEDIA_ERR_NONE) {
266                 if (ret == MS_MEDIA_ERR_DB_CORRUPT && retry_cnt == 0) {
267                         retry_cnt++;
268
269                         ret = ms_ipc_request_recovery(uid);
270                         if (ret == MS_MEDIA_ERR_NONE)
271                                 goto RETRY_CONN;
272                         else
273                                 return MS_MEDIA_ERR_DB_CORRUPT;
274                 } else {
275                         return ret;
276                 }
277         }
278
279         *handle = db_handle;
280         return MS_MEDIA_ERR_NONE;
281 }
282
283 void media_db_disconnect(sqlite3 *handle)
284 {
285         MSAPI_DBG_FUNC();
286
287         if (handle) {
288                 sqlite3_close_v2(handle);
289                 handle = NULL;
290         }
291 }
292
293 int media_db_request_update_db(const char *query_str, uid_t uid)
294 {
295         int ret = MS_MEDIA_ERR_NONE;
296
297         MSAPI_DBG_FUNC();
298
299         MSAPI_RETVM_IF(!query_str || strlen(query_str) == 0, MS_MEDIA_ERR_INVALID_PARAMETER, "Invalid Query");
300
301 #ifdef _USE_ON_DEMAND
302         ret = ms_ipc_activate_media_server();
303         if (ret != MS_MEDIA_ERR_NONE) {
304                 MSAPI_DBG_ERR("ms_ipc_activate_media_server failed : %d", ret);
305                 return ret;
306         }
307 #endif
308         ret = ms_ipc_request_update_db(query_str, uid);
309
310         if (ret != MS_MEDIA_ERR_NONE)
311                 MSAPI_DBG_ERR("ms_ipc_request_update_db failed : %d", ret);
312
313         return ret;
314 }
315
316 int media_db_update_db_direct(const char *query_str, uid_t uid)
317 {
318         int ret = MS_MEDIA_ERR_NONE;
319         sqlite3 *handle = NULL;
320
321         MSAPI_DBG_FUNC();
322
323         MSAPI_RETVM_IF(!query_str || strlen(query_str) == 0, MS_MEDIA_ERR_INVALID_PARAMETER, "Invalid Query");
324
325         ret = media_db_connect(&handle, uid, true);
326         MSAPI_RETVM_IF(ret != MS_MEDIA_ERR_NONE, ret, "Connect failed");
327
328         ret = __media_db_update_directly(handle, query_str);
329         if (ret != MS_MEDIA_ERR_NONE)
330                 MSAPI_DBG_ERR("Query failed");
331
332         media_db_disconnect(handle);
333
334         return ret;
335 }
336
337 int media_db_get_result(sqlite3 *handle, const char *sql_str, sqlite3_stmt **stmt)
338 {
339         int err = SQLITE_OK;
340
341         MSAPI_RETVM_IF(!sql_str, MS_MEDIA_ERR_INVALID_PARAMETER, "invalid query");
342         MSAPI_RETVM_IF(!handle, MS_MEDIA_ERR_INVALID_PARAMETER, "handle is null");
343
344         MSAPI_DBG_SLOG("[SQL query] : %s", sql_str);
345
346         err = sqlite3_prepare_v2(handle, sql_str, -1, stmt, NULL);
347         if (err != SQLITE_OK) {
348                 MSAPI_DBG_ERR("prepare error %d[%s]", err, sqlite3_errmsg(handle));
349                 if (err == SQLITE_CORRUPT)
350                         return MS_MEDIA_ERR_DB_CORRUPT;
351
352                 return MS_MEDIA_ERR_DB_INTERNAL;
353         }
354
355         return MS_MEDIA_ERR_NONE;
356 }