4 * Copyright (c) 2012 - 2015 Samsung Electronics Co., Ltd. All rights reserved.
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
25 #include <sys/types.h>
27 #include "cal_internal.h"
28 #include "cal_typedef.h"
30 #include "cal_db_util.h"
31 #include "cal_utils.h"
33 #define CAL_QUERY_RETRY_TIME 4
34 #define CAL_COMMIT_TRY_MAX 500000
35 #define CAL_QUERY_RETRY_INTERVAL (50*1000)
36 #define CAL_CHANGES_EVENT 0x01
37 #define CAL_CHANGES_TODO 0x02
38 #define CAL_CHANGES_CALENDAR 0x04
40 static TLS sqlite3 *cal_db = NULL;
41 static TLS int transaction_cnt = 0;
42 static TLS int transaction_ver = 0;
43 static TLS bool version_up = false;
45 static TLS bool event_change = false;
46 static TLS bool todo_change = false;
47 static TLS bool calendar_change = false;
49 static void _cal_db_util_notify_event_change(void)
51 int fd = open(CAL_NOTI_FILE_EVENT, O_TRUNC | O_RDWR);
62 static inline void _cal_db_util_notify_todo_change(void)
64 int fd = open(CAL_NOTI_FILE_TODO, O_TRUNC | O_RDWR);
75 static inline void _cal_db_util_notify_calendar_change(void)
77 int fd = open(CAL_NOTI_FILE_BOOK, O_TRUNC | O_RDWR);
80 calendar_change = false;
88 static inline void _cal_db_util_cancel_changes(void)
91 calendar_change = false;
95 int cal_db_util_notify(cal_noti_type_e type)
97 if (0 < transaction_cnt) {
99 case CAL_NOTI_TYPE_EVENT:
102 case CAL_NOTI_TYPE_TODO:
105 case CAL_NOTI_TYPE_BOOK:
106 calendar_change = true;
109 /* LCOV_EXCL_START */
110 ERR("The type(%d) is not supported", type);
111 return CALENDAR_ERROR_INVALID_PARAMETER;
114 return CALENDAR_ERROR_NONE;
118 case CAL_NOTI_TYPE_EVENT:
119 _cal_db_util_notify_event_change();
121 case CAL_NOTI_TYPE_TODO:
122 _cal_db_util_notify_todo_change();
124 case CAL_NOTI_TYPE_BOOK:
125 _cal_db_util_notify_calendar_change();
128 /* LCOV_EXCL_START */
129 ERR("The type(%d) is not supported", type);
130 return CALENDAR_ERROR_INVALID_PARAMETER;
134 return CALENDAR_ERROR_NONE;
137 int cal_db_util_open(void)
140 return CALENDAR_ERROR_NONE;
142 if (-1 == access(DB_PATH, F_OK))
145 if (-1 == access(CAL_DB_FILE, F_OK))
149 ret = db_util_open(CAL_DB_FILE, &cal_db, 0);
150 if (SQLITE_OK != ret) {
151 /* LCOV_EXCL_START */
152 ERR("db_util_open() Fail(%d).", ret);
153 return CALENDAR_ERROR_DB_FAILED;
157 return CALENDAR_ERROR_NONE;
160 int cal_db_util_close(void)
163 return CALENDAR_ERROR_NONE;
166 ret = db_util_close(cal_db);
167 if (SQLITE_OK != ret)
168 WARN("db_util_close() Fail(%d)", ret);
171 DBG("The database disconnected really.");
173 return CALENDAR_ERROR_NONE;
176 int cal_db_util_last_insert_id(void)
178 return sqlite3_last_insert_rowid(cal_db);
181 int cal_db_util_query_prepare(char *query, sqlite3_stmt **stmt)
185 RETV_IF(NULL == cal_db, CALENDAR_ERROR_INVALID_PARAMETER);
186 RETV_IF(NULL == query, CALENDAR_ERROR_INVALID_PARAMETER);
187 RETV_IF(NULL == stmt, CALENDAR_ERROR_INVALID_PARAMETER);
189 struct timeval from, now, diff;
190 gettimeofday(&from, NULL);
194 ret = sqlite3_prepare_v2(cal_db, query, strlen(query), stmt, NULL);
195 if (SQLITE_BUSY == ret || SQLITE_LOCKED == ret) {
196 gettimeofday(&now, NULL);
197 timersub(&now, &from, &diff);
198 retry = (diff.tv_sec < CAL_QUERY_RETRY_TIME) ? true : false;
200 usleep(CAL_QUERY_RETRY_INTERVAL); /* 50ms */
208 ret = CALENDAR_ERROR_NONE;
211 /* LCOV_EXCL_START */
213 ret = CALENDAR_ERROR_DB_FAILED;
217 /* LCOV_EXCL_START */
218 ERR("SQLITE_LOCKED");
219 ret = CALENDAR_ERROR_DB_FAILED;
223 /* LCOV_EXCL_START */
224 ERR("ERROR(%d)", ret);
225 ret = CALENDAR_ERROR_DB_FAILED;
232 int cal_db_util_stmt_step(sqlite3_stmt *stmt)
235 RETV_IF(NULL == stmt, CALENDAR_ERROR_INVALID_PARAMETER);
237 struct timeval from, now, diff;
240 gettimeofday(&from, NULL);
242 ret = sqlite3_step(stmt);
243 if (SQLITE_BUSY == ret || SQLITE_LOCKED == ret) {
244 gettimeofday(&now, NULL);
245 timersub(&now, &from, &diff);
246 retry = (diff.tv_sec < CAL_QUERY_RETRY_TIME) ? true : false;
248 usleep(CAL_QUERY_RETRY_INTERVAL); /* 50ms */
256 ret = CAL_SQLITE_ROW; /* TRUE */
259 ret = CALENDAR_ERROR_NONE;
262 /* LCOV_EXCL_START */
264 ret = CALENDAR_ERROR_DB_FAILED;
268 /* LCOV_EXCL_START */
269 ERR("SQLITE_LOCKED");
270 ret = CALENDAR_ERROR_DB_FAILED;
274 /* LCOV_EXCL_START */
275 ERR("ERROR(%d)", ret);
276 ret = CALENDAR_ERROR_DB_FAILED;
283 int cal_db_util_query_exec(char *query)
286 RETV_IF(NULL == cal_db, CALENDAR_ERROR_INVALID_PARAMETER);
287 RETV_IF(NULL == query, CALENDAR_ERROR_INVALID_PARAMETER);
289 sqlite3_stmt *stmt = NULL;
290 ret = cal_db_util_query_prepare(query, &stmt);
291 if (CALENDAR_ERROR_NONE != ret) {
292 /* LCOV_EXCL_START */
293 ERR("cal_db_util_query_prepare() Fail(%d)", ret);
298 ret = cal_db_util_stmt_step(stmt);
299 if (CALENDAR_ERROR_NONE != ret) {
300 /* LCOV_EXCL_START */
301 ERR("cal_db_util_stmt_step() Fail(%d)", ret);
302 SECURE("query[%s]", query);
303 sqlite3_finalize(stmt);
307 sqlite3_finalize(stmt);
309 return CALENDAR_ERROR_NONE;
312 int cal_db_util_query_get_first_int_result(const char *query, GSList *bind_text, int *result)
315 RETV_IF(NULL == cal_db, CALENDAR_ERROR_INVALID_PARAMETER);
316 RETV_IF(NULL == query, CALENDAR_ERROR_INVALID_PARAMETER);
317 RETV_IF(NULL == result, CALENDAR_ERROR_INVALID_PARAMETER);
319 struct timeval from, now, diff;
320 gettimeofday(&from, NULL);
323 sqlite3_stmt *stmt = NULL;
325 ret = sqlite3_prepare_v2(cal_db, query, strlen(query), &stmt, NULL);
326 if (SQLITE_BUSY == ret || SQLITE_LOCKED == ret) {
327 /* LCOV_EXCL_START */
328 ERR("sqlite3_prepare_v2() Fail:[%s]", sqlite3_errmsg(cal_db));
329 SECURE("[%s]", query);
330 gettimeofday(&now, NULL);
331 timersub(&now, &from, &diff);
332 retry = (diff.tv_sec < CAL_QUERY_RETRY_TIME) ? true : false;
334 usleep(CAL_QUERY_RETRY_INTERVAL); /* 50ms */
341 if (SQLITE_OK != ret) {
342 /* LCOV_EXCL_START */
343 ERR("sqlite3_prepare_v2(%s) Fail(%s).", query, sqlite3_errmsg(cal_db));
344 SECURE("query[%s]", query);
345 return CALENDAR_ERROR_DB_FAILED;
351 for (i = 0; g_slist_nth(bind_text, i); i++) {
352 char *text = (char *)g_slist_nth_data(bind_text, i);
354 cal_db_util_stmt_bind_text(stmt, i +1, text);
359 gettimeofday(&from, NULL);
361 ret = sqlite3_step(stmt);
362 if (SQLITE_BUSY == ret || SQLITE_LOCKED == ret) {
363 /* LCOV_EXCL_START */
364 ERR("sqlite3_step fail(%d, %s)", ret, sqlite3_errmsg(cal_db));
365 gettimeofday(&now, NULL);
366 timersub(&now, &from, &diff);
367 retry = (diff.tv_sec < CAL_QUERY_RETRY_TIME) ? true : false;
369 usleep(CAL_QUERY_RETRY_INTERVAL); /* 50ms */
376 if (SQLITE_ROW == ret) {
377 *result = sqlite3_column_int(stmt, 0);
378 sqlite3_finalize(stmt);
379 return CALENDAR_ERROR_NONE;
381 sqlite3_finalize(stmt);
386 ret = CALENDAR_ERROR_NO_DATA;
389 /* LCOV_EXCL_START */
391 ret = CALENDAR_ERROR_DB_FAILED;
395 /* LCOV_EXCL_START */
396 ERR("SQLITE_LOCKED");
397 ret = CALENDAR_ERROR_DB_FAILED;
401 /* LCOV_EXCL_START */
402 ERR("ERROR(%d)", ret);
403 ret = CALENDAR_ERROR_DB_FAILED;
407 return CALENDAR_ERROR_NONE;
410 int cal_db_util_begin_trans(void)
412 if (transaction_cnt <= 0) {
416 ret = cal_db_util_query_exec("BEGIN IMMEDIATE TRANSACTION");
417 /* !! check error code */
418 while (CALENDAR_ERROR_NONE != ret && progress < CAL_COMMIT_TRY_MAX) {
420 ret = cal_db_util_query_exec("BEGIN IMMEDIATE TRANSACTION");
423 RETVM_IF(CALENDAR_ERROR_NONE != ret, ret, "cal_query_exec() Fail(%d)", ret);
426 const char *query = "SELECT ver FROM "CAL_TABLE_VERSION;
427 ret = cal_db_util_query_get_first_int_result(query, NULL, &transaction_ver);
428 if (CALENDAR_ERROR_NONE != ret) {
429 /* LCOV_EXCL_START */
430 ERR("cal_db_util_query_get_first_int_result() Fail");
437 DBG("transaction_cnt : %d", transaction_cnt);
439 return CALENDAR_ERROR_NONE;
442 int cal_db_util_end_trans(bool is_success)
446 char query[CAL_DB_SQL_MIN_LEN];
450 if (0 != transaction_cnt) {
451 DBG("transaction_cnt : %d", transaction_cnt);
452 return CALENDAR_ERROR_NONE;
455 if (false == is_success) {
456 _cal_db_util_cancel_changes();
457 ret = cal_db_util_query_exec("ROLLBACK TRANSACTION");
458 return CALENDAR_ERROR_NONE;
463 snprintf(query, sizeof(query), "UPDATE %s SET ver = %d",
464 CAL_TABLE_VERSION, transaction_ver);
465 ret = cal_db_util_query_exec(query);
466 WARN_IF(CALENDAR_ERROR_NONE != ret, "cal_query_exec(version up) Fail(%d).", ret);
469 INFO("start commit");
471 ret = cal_db_util_query_exec("COMMIT TRANSACTION");
472 /* !! check error code */
473 while (CALENDAR_ERROR_NONE != ret && progress < CAL_COMMIT_TRY_MAX) {
475 ret = cal_db_util_query_exec("COMMIT TRANSACTION");
478 INFO("%s", (CALENDAR_ERROR_NONE == ret) ? "commit" : "rollback");
480 if (CALENDAR_ERROR_NONE != ret) {
482 /* LCOV_EXCL_START */
483 ERR("cal_query_exec() Fail(%d)", ret);
484 _cal_db_util_cancel_changes();
485 tmp_ret = cal_db_util_query_exec("ROLLBACK TRANSACTION");
486 WARN_IF(CALENDAR_ERROR_NONE != tmp_ret, "cal_query_exec(ROLLBACK) Fail(%d).", tmp_ret);
487 return CALENDAR_ERROR_DB_FAILED;
490 if (event_change) _cal_db_util_notify_event_change();
491 if (todo_change) _cal_db_util_notify_todo_change();
492 if (calendar_change) _cal_db_util_notify_calendar_change();
494 DBG("transaction_ver = %d", transaction_ver);
495 return CALENDAR_ERROR_NONE;
498 int cal_db_util_get_next_ver(void)
501 if (0 < transaction_cnt) {
503 return transaction_ver + 1;
507 const char *query = "SELECT ver FROM "CAL_TABLE_VERSION;
508 ret = cal_db_util_query_get_first_int_result(query, NULL, &count);
509 if (CALENDAR_ERROR_NONE != ret)
510 WARN("cal_db_util_query_get_first_int_result() Fail(%d)", ret);
515 int cal_db_util_get_transaction_ver(void)
517 return transaction_ver;
520 int cal_db_util_stmt_bind_text(sqlite3_stmt *stmt, int pos, const char *str)
522 return sqlite3_bind_text(stmt, pos, str, str ? strlen(str) : 0, SQLITE_STATIC);