2 * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
25 #include "ua-manager-common.h"
26 #include "ua-manager-database.h"
28 #define UAM_DB_USERDATA_TABLE "userdata" /**< User data DB table name */
29 #define UAM_DB_DEVICES_TABLE "devices" /**< Device DB table name */
30 #define UAM_DB_SERVICES_TABLE "services" /**< Service DB table name */
31 #define UAM_DB_DEVICE_SERVICES_TABLE "device_services" /**< Device services DB table name */
32 #define UAM_DB_IBEACON_ADV_TABLE "ibeacon_adv" /**< iBeacon adv DB table name */
34 #define CREATE_USERDATA_TABLE "CREATE TABLE IF NOT EXISTS userdata ( " \
36 "user_id INTEGER PRIMARY KEY AUTOINCREMENT, " \
41 #define CREATE_DEVICES_TABLE "CREATE TABLE IF NOT EXISTS devices ( " \
42 "device_number INTEGER PRIMARY KEY AUTOINCREMENT, " \
45 "tech_type INTEGER, " \
49 "presence_state INTEGER, " \
51 "discriminant INTEGER, " \
55 "device_icon TEXT, " \
56 "FOREIGN KEY(user_id) REFERENCES userdata(user_id), " \
57 "UNIQUE (device_id, tech_type) " \
60 #define CREATE_SERVICES_TABLE "CREATE TABLE IF NOT EXISTS services ( " \
61 "service_number INTEGER PRIMARY KEY AUTOINCREMENT, " \
62 "service_name TEXT, " \
64 "presence_threshold INTEGER, " \
65 "absence_threshold INTEGER, " \
66 "UNIQUE (service_name) " \
69 #define CREATE_DEVICE_SERVICES_TABLE "CREATE TABLE IF NOT EXISTS device_services ( " \
70 "device_number INTEGER, " \
71 "service_number INTEGER, " \
72 "discriminant INTEGER, " \
74 "FOREIGN KEY(device_number) REFERENCES devices(device_number), " \
75 "FOREIGN KEY(service_number) REFERENCES services(service_number), " \
76 "PRIMARY KEY(device_number, service_number) " \
79 #define CREATE_IBEACON_ADV_TABLE "CREATE TABLE IF NOT EXISTS ibeacon_adv ( " \
80 "ibeacon_id INTEGER PRIMARY KEY AUTOINCREMENT, " \
81 "ibeacon_adv TEXT, " \
83 "UNIQUE (ibeacon_adv) " \
88 sqlite3 *database_handle;
89 static sqlite3_stmt *select_version;
90 static int transaction_cnt;
92 static int __uam_db_exec_sql(char *sql, void *cb)
98 if (NULL == database_handle) {
99 UAM_ERR("database_handle is NULL");
100 return UAM_ERROR_DB_FAILED;
104 UAM_ERR("sql is NULL");
105 return UAM_ERROR_DB_FAILED;
108 sql_ret = sqlite3_exec(database_handle, sql, cb, NULL, &error);
109 if (SQLITE_OK != sql_ret) {
110 UAM_ERR("Failed to execute sql: (%d) %s", sql_ret, error);
112 sqlite3_close(database_handle);
113 database_handle = NULL;
114 return UAM_ERROR_DB_FAILED;
117 return UAM_ERROR_NONE;
120 static int __uam_db_open(void)
125 res = sqlite3_open_v2(DATABASE_FULL_PATH, &(database_handle),
126 SQLITE_OPEN_FULLMUTEX | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
127 if (SQLITE_OK != res) {
128 UAM_ERR("sqlite3_open_v2 failed, (%d)", res);
130 return UAM_ERROR_DB_FAILED;
132 UAM_DBG("Successfully opened database");
138 static int __uam_db_busy(void *data, int attempt)
141 int max_attempts = SQLITE_MAX_RETRY;
143 if (attempt < max_attempts) {
144 UAM_WARN("DB locked, attempt number %d, Attempt Remaining %d",
145 attempt, max_attempts - attempt);
146 usleep(SQLITE_BUSY_TIMEOUT); /* wait for a half second*/
150 UAM_ERR("DB locked by another process, attempts tried %d, Exit",
156 static int __uam_db_get_version(unsigned int *ver)
159 int error_code = UAM_ERROR_NONE;
162 sql = sqlite3_mprintf("PRAGMA user_version");
163 sqlite3_stmt *stmt = select_version;
165 sql_ret = sqlite3_prepare_v2(database_handle, sql, -1, &stmt, NULL);
166 if (sql_ret != SQLITE_OK) {
168 FINALIZE(select_version);
169 UAM_ERR("Failed to prepare \"%s\" query", sql);
175 sql_ret = sqlite3_step(stmt);
181 *ver = sqlite3_column_int(stmt, 0);
182 UAM_INFO("database version %d", *ver);
186 UAM_ERR("Failed to select database version info [%d:%s]",
187 sql_ret, sqlite3_errmsg(database_handle));
189 } while (sql_ret == SQLITE_ROW);
191 FINALIZE(select_version);
193 sqlite3_finalize(stmt);
199 static int __uam_db_update_version(unsigned int version)
203 int ret = UAM_ERROR_NONE;
205 sql = sqlite3_mprintf("PRAGMA user_version = '%d';", version);
207 ret = __uam_db_exec_sql(sql, NULL);
208 if (UAM_ERROR_NONE != ret)
209 UAM_DBG("failed to updated database version to %d", version);
211 UAM_DBG("Successfully updated database version to %d", version);
219 static int __uam_db_upgrade(unsigned int version)
223 This code should handle all the database upgrade after initial version
226 /* update database version */
227 retv_if(UAM_ERROR_NONE != __uam_db_update_version(version), UAM_ERROR_DB_FAILED);
228 UAM_DBG("Successfully upgraded database version to %d", version);
231 return UAM_ERROR_NONE;
234 static int __uam_db_upgrade_version(unsigned int old_ver, unsigned int new_ver)
237 int ret = UAM_ERROR_NONE;
240 for (i = old_ver + 1; i <= new_ver; i++) {
241 ret = __uam_db_upgrade(i);
242 if (UAM_ERROR_NONE != ret) {
243 UAM_ERR("Faild to __uam_db_upgrade(%d)", i);
244 ret = UAM_ERROR_DB_FAILED;
253 int _uam_db_check_version(void)
256 unsigned int curr_ver = VERSION;
257 unsigned int old_ver = 0;
259 /* check database version */
260 retv_if(UAM_ERROR_NONE != __uam_db_get_version(&old_ver), UAM_ERROR_DB_FAILED);
263 retv_if(UAM_ERROR_NONE != __uam_db_update_version(curr_ver), UAM_ERROR_DB_FAILED);
264 } else if (old_ver != curr_ver) {
265 UAM_DBG("Database version changed, needs upgrade");
266 /* upgrade database to new version */
267 retv_if(UAM_ERROR_NONE != __uam_db_upgrade_version(old_ver, curr_ver), UAM_ERROR_DB_FAILED);
271 return UAM_ERROR_NONE;
274 static bool __uam_db_is_table_existing(const char *table)
279 int sql_ret = SQLITE_OK;
281 sql = sqlite3_mprintf(
282 "SELECT count(*) FROM sqlite_master WHERE type='table' AND name ='%s';", table);
284 UAM_ERR("sqlite3_mprintf failed");
287 sqlite3_stmt *stmt = NULL;
289 sql_ret = sqlite3_prepare_v2(database_handle, sql, strlen(sql), &stmt, NULL);
290 if (SQLITE_OK != sql_ret) {
291 UAM_ERR("sqlite3_prepare_v2 failed, [%d:%s]", sql_ret, sqlite3_errmsg(database_handle));
293 goto is_table_existing_done;
296 sql_ret = sqlite3_step(stmt);
297 if (sql_ret != SQLITE_ROW) {
298 UAM_ERR("sqlite3_step failed, [%d:%s]", sql_ret, sqlite3_errmsg(database_handle));
300 goto is_table_existing_done;
303 count = sqlite3_column_int(stmt, 0);
309 is_table_existing_done:
310 sqlite3_finalize(stmt);
316 static int __uam_db_check_integrity_cb(
317 void *err, int count, char **data, char **columns)
321 UAM_DBG("%s = %s\n", columns[0], data[0] ? data[0] : "NULL");
322 if (!g_strcmp0(columns[0], "integrity_check") && !g_strcmp0(data[0], "ok"))
328 static int __uam_db_check_integrity(void)
331 int ret = UAM_ERROR_NONE;
334 sql = sqlite3_mprintf("PRAGMA integrity_check");
336 ret = __uam_db_exec_sql(sql, __uam_db_check_integrity_cb);
337 if (UAM_ERROR_NONE != ret)
338 UAM_ERR("Faild to __uam_db_exec_sql()");
340 UAM_DBG("Successfully verified database integrity");
348 static int __uam_db_set_locking_mode(void)
351 int ret = UAM_ERROR_NONE;
353 sql = sqlite3_mprintf("PRAGMA locking_mode = NORMAL");
354 ret = __uam_db_exec_sql(sql, NULL);
355 if (UAM_ERROR_NONE != ret)
356 ret = UAM_ERROR_DB_FAILED;
363 static int __uam_db_create_table(const char *table_name)
366 int ret = UAM_ERROR_NONE;
368 sql = sqlite3_mprintf(table_name);
369 ret = __uam_db_exec_sql(sql, NULL);
371 if (UAM_ERROR_NONE != ret)
372 UAM_ERR("Faild to __uam_db_exec_sql()");
374 UAM_DBG("Successfully created table %s", table_name);
381 static int __uam_db_check_table_creation(void)
384 int error_code = UAM_ERROR_DB_FAILED;
386 if (!__uam_db_is_table_existing(UAM_DB_USERDATA_TABLE))
387 retv_if(UAM_ERROR_NONE != __uam_db_create_table(CREATE_USERDATA_TABLE), error_code);
389 if (!__uam_db_is_table_existing(UAM_DB_DEVICES_TABLE))
390 retv_if(UAM_ERROR_NONE != __uam_db_create_table(CREATE_DEVICES_TABLE), error_code);
392 if (!__uam_db_is_table_existing(UAM_DB_SERVICES_TABLE))
393 retv_if(UAM_ERROR_NONE != __uam_db_create_table(CREATE_SERVICES_TABLE), error_code);
395 if (!__uam_db_is_table_existing(UAM_DB_DEVICE_SERVICES_TABLE))
396 retv_if(UAM_ERROR_NONE != __uam_db_create_table(CREATE_DEVICE_SERVICES_TABLE), error_code);
398 if (!__uam_db_is_table_existing(UAM_DB_IBEACON_ADV_TABLE))
399 retv_if(UAM_ERROR_NONE != __uam_db_create_table(CREATE_IBEACON_ADV_TABLE), error_code);
401 UAM_DBG("Successfully verified table creation");
403 return UAM_ERROR_NONE;
406 static int __uam_db_verify()
410 /* check table existance*/
411 retv_if(UAM_ERROR_NONE != __uam_db_check_table_creation(), UAM_ERROR_DB_FAILED);
413 _uam_get_file_size(DATABASE_FULL_PATH);
414 /* check db integrity */
415 retv_if(UAM_ERROR_NONE != __uam_db_check_integrity(), UAM_ERROR_DB_FAILED);
416 /* set locking mode */
417 retv_if(UAM_ERROR_NONE != __uam_db_set_locking_mode(), UAM_ERROR_DB_FAILED);
419 UAM_DBG("Successfully verified database");
421 return UAM_ERROR_NONE;
424 int _uam_db_initialize_once(void)
428 int ret = UAM_ERROR_NONE;
433 retv_if(SQLITE_OK != __uam_db_open(), UAM_ERROR_DB_FAILED);
435 if (UAM_ERROR_NONE != __uam_db_verify()) {
436 UAM_ERR("Failed to verify database");
437 sqlite3_close(database_handle);
438 unlink(DATABASE_FULL_PATH);
439 database_handle = NULL;
440 retv_if(0 == max_retries, UAM_ERROR_DB_FAILED);
444 } while (max_retries--);
446 /* Enable persist journal mode */
447 sql = sqlite3_mprintf("PRAGMA journal_mode = PERSIST");
448 ret = __uam_db_exec_sql(sql, NULL);
450 if (UAM_ERROR_NONE != ret) {
451 UAM_ERR("Faile to __uam_db_exec_sql()");
452 return UAM_ERROR_DB_FAILED;
455 if (NULL == database_handle) {
456 unlink(DATABASE_FULL_PATH);
457 return UAM_ERROR_DB_FAILED;
460 /* Set how many times we'll repeat our attempts for sqlite_step */
461 if (SQLITE_OK != sqlite3_busy_handler(database_handle, __uam_db_busy, NULL)) {
462 UAM_ERR("Couldn't set busy handler!");
463 return UAM_ERROR_DB_FAILED;
470 int _uam_db_initialize(void)
473 database_handle = NULL;
475 /* initialize database */
476 EXEC(UAM_ERROR_NONE, _uam_db_initialize_once(), handle_error);
478 /* check database version */
479 EXEC(UAM_ERROR_NONE, _uam_db_check_version(), handle_error);
481 /* initialize tables */
482 EXEC(UAM_ERROR_NONE, _uam_user_db_initialize(), handle_error);
483 EXEC(UAM_ERROR_NONE, _uam_device_db_initialize(), handle_error);
484 EXEC(UAM_ERROR_NONE, _uam_service_db_initialize(), handle_error);
485 EXEC(UAM_ERROR_NONE, _uam_device_service_db_initialize(), handle_error);
486 EXEC(UAM_ERROR_NONE, _uam_adv_db_initialize(), handle_error);
490 return UAM_ERROR_NONE;
493 _uam_db_deinitialize();
495 return UAM_ERROR_DB_FAILED;
498 int _uam_db_deinitialize(void)
502 retv_if(NULL == database_handle, UAM_ERROR_NONE);
504 _uam_user_db_deinitialize();
505 _uam_device_db_deinitialize();
506 _uam_service_db_deinitialize();
507 _uam_device_service_db_deinitialize();
508 _uam_adv_db_deinitialize();
511 return UAM_ERROR_NONE;
514 int _uam_db_clear(void)
516 int error_code = UAM_ERROR_DB_FAILED;
517 retv_if(NULL == database_handle, UAM_ERROR_DB_FAILED);
519 EXEC(UAM_ERROR_NONE, _uam_user_db_clear(), handle_error);
520 EXEC(UAM_ERROR_NONE, _uam_device_db_clear(), handle_error);
521 EXEC(UAM_ERROR_NONE, _uam_service_db_clear(), handle_error);
522 EXEC(UAM_ERROR_NONE, _uam_device_service_db_clear(), handle_error);
523 EXEC(UAM_ERROR_NONE, _uam_adv_db_clear(), handle_error);
524 UAM_DBG("Table data deleted ");
526 error_code = UAM_ERROR_NONE;
532 int __uam_db_begin_transaction(void)
536 int ret = UAM_ERROR_NONE;
538 if (transaction_cnt <= 0) {
540 sql = sqlite3_mprintf("BEGIN IMMEDIATE TRANSACTION");
542 ret = __uam_db_exec_sql(sql, NULL);
543 if (UAM_ERROR_NONE != ret)
544 UAM_DBG("failed to begin transaction");
546 UAM_DBG("Successful to begin transaction");
551 UAM_DBG("transaction_cnt: %d", transaction_cnt);
557 static int __uam_db_rollback_transaction(void)
561 int ret = UAM_ERROR_NONE;
563 sql = sqlite3_mprintf("ROLLBACK TRANSACTION");
565 ret = __uam_db_exec_sql(sql, NULL);
566 if (UAM_ERROR_NONE != ret)
567 UAM_DBG("failed to rollback transaction");
569 UAM_DBG("Successful to rollback transaction");
577 int __uam_db_end_transaction(gboolean is_success)
581 int ret = UAM_ERROR_NONE;
585 if (0 != transaction_cnt) {
586 UAM_DBG("transaction_cnt: %d", transaction_cnt);
590 if (false == is_success) {
591 ret = __uam_db_rollback_transaction();
595 sql = sqlite3_mprintf("COMMIT TRANSACTION");
597 ret = __uam_db_exec_sql(sql, NULL);
598 if (UAM_ERROR_NONE != ret) {
599 UAM_DBG("failed to commit transaction");
600 ret = __uam_db_rollback_transaction();
602 UAM_DBG("Successful to commit transaction");