2 * Copyright (c) 2014 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.
30 #include "MsgSqliteWrapper.h"
32 int __msg_db_util_open(const char *pszFilePath, sqlite3 **ppDB, int flags, const char *zVfs);
33 int __msg_db_util_close(sqlite3 *pDB);
34 void __clear_db_handle(sqlite3 *pDB);
36 /*==================================================================================================
38 ==================================================================================================*/
40 __thread sqlite3 *handle = NULL;
41 __thread sqlite3_stmt *stmt = NULL;
44 /*==================================================================================================
45 IMPLEMENTATION OF MsgDbHandler - Member Functions
46 ==================================================================================================*/
47 MsgDbHandler::MsgDbHandler()
58 MsgDbHandler::~MsgDbHandler()
62 if (disconnect() != MSG_SUCCESS)
63 MSG_DEBUG("DB disconnect is failed.");
66 msg_error_t MsgDbHandler::connect()
73 memset(strDBName, 0x00, sizeof(strDBName));
74 snprintf(strDBName, 64, "%s", MSGFW_DB_NAME);
76 ret = __msg_db_util_open(strDBName, &handle, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
78 if (ret == SQLITE_OK) {
79 MSG_DEBUG("DB Connect Success : [%p]", handle);
81 } else if (ret == SQLITE_PERM){
82 MSG_DEBUG("DB Connect Fail [%d]", ret);
83 return MSG_ERR_PERMISSION_DENIED;
85 MSG_DEBUG("DB Connect Fail [%d]", ret);
86 return MSG_ERR_DB_CONNECT;
89 MSG_DEBUG("DB Connect exist : [%p]", handle);
95 /* Use only in app side */
96 msg_error_t MsgDbHandler::connectReadOnly()
100 if (handle == NULL) {
103 memset(strDBName, 0x00, sizeof(strDBName));
104 snprintf(strDBName, 64, "%s", MSGFW_DB_NAME);
106 MSG_DEBUG("db_util_open_with_options SQLITE_OPEN_READONLY");
107 ret = __msg_db_util_open(strDBName, &handle, SQLITE_OPEN_READONLY, NULL);
109 if (ret == SQLITE_OK) {
110 MSG_DEBUG("DB Connect Success : [%p]", handle);
112 } else if (ret == SQLITE_PERM){
113 MSG_DEBUG("DB Connect Fail [%d]", ret);
114 return MSG_ERR_PERMISSION_DENIED;
116 MSG_DEBUG("DB Connect Fail [%d]", ret);
117 return MSG_ERR_DB_CONNECT;
120 MSG_DEBUG("DB Connect exist : [%p]", handle);
127 msg_error_t MsgDbHandler::disconnect()
131 if (handle != NULL) {
132 ret = __msg_db_util_close(handle);
134 if (ret == SQLITE_OK) {
136 MSG_DEBUG("DB Disconnect Success");
139 MSG_DEBUG("DB Disconnect Fail [%d]", ret);
140 return MSG_ERR_DB_DISCONNECT;
148 bool MsgDbHandler::checkTableExist(const char *pTableName)
151 int nRowCnt = 0, nResult = 0;
153 /* Formulate the Query */
154 memset(strQuery, 0x00, sizeof(strQuery));
155 snprintf(strQuery, sizeof(strQuery), "select count(name) from sqlite_master where name='%s'", pTableName);
157 if (getTable(strQuery, &nRowCnt, NULL) != MSG_SUCCESS) {
162 nResult = getColumnToInt(1);
163 MSG_DEBUG("Result [%d]", nResult);
174 msg_error_t MsgDbHandler::execQuery(const char *pQuery)
177 return MSG_ERR_INVALID_PARAMETER;
179 if(connect() != MSG_SUCCESS)
180 return MSG_ERR_DB_DISCONNECT;
182 if (prepareQuery(pQuery) != MSG_SUCCESS) {
183 MSG_DEBUG("Fail to prepareQuery.");
184 return MSG_ERR_DB_EXEC;
187 if (stepQuery() == MSG_ERR_DB_STEP) {
188 MSG_DEBUG("Fail to stepQuery.");
190 return MSG_ERR_DB_EXEC;
199 msg_error_t MsgDbHandler::getTable(const char *pQuery, int *pRowCnt, int *pColumnCnt)
207 if(connect() != MSG_SUCCESS)
208 return MSG_ERR_DB_DISCONNECT;
211 MSG_DEBUG("[%s]", pQuery);
212 ret = sqlite3_get_table(handle, pQuery, &result, pRowCnt, pColumnCnt, NULL);
214 if (ret == SQLITE_OK) {
215 if (*pRowCnt == 0) { /* when the no record return 'MSG_ERR_DB_NORECORD' */
216 MSG_DEBUG("No Query Result");
217 return MSG_ERR_DB_NORECORD;
220 MSG_DEBUG("Get Table Success");
222 } else if (ret == SQLITE_BUSY) {
223 MSG_DEBUG("The database file is locked [%d]", ret);
224 return MSG_ERR_DB_BUSY;
226 MSG_DEBUG("Get Table Fail [%d]", ret);
227 return MSG_ERR_DB_GETTABLE;
234 msg_error_t MsgDbHandler::getTableWithResult(const char *pQuery, char ***res, int *pRowCnt, int *pColumnCnt)
242 MSG_DEBUG("[%s]", pQuery);
243 ret = sqlite3_get_table(handle, pQuery, res, pRowCnt, pColumnCnt, NULL);
245 if (ret == SQLITE_OK) {
246 if (*pRowCnt == 0) { /* when the no record return 'MSG_ERR_DB_NORECORD' */
247 MSG_DEBUG("No Query Result");
248 return MSG_ERR_DB_NORECORD;
251 MSG_DEBUG("Get Table Success");
253 } else if (ret == SQLITE_BUSY) {
254 MSG_DEBUG("The database file is locked [%d]", ret);
255 return MSG_ERR_DB_BUSY;
257 MSG_DEBUG("Get Table Fail [%d]", ret);
258 return MSG_ERR_DB_GETTABLE;
264 void MsgDbHandler::freeTable()
267 sqlite3_free_table(result);
272 void MsgDbHandler::freeTable(char **db_res)
275 sqlite3_free_table(db_res);
280 msg_error_t MsgDbHandler::bindText(const char *pBindStr, int index)
284 if (pBindStr != NULL)
285 ret = sqlite3_bind_text(stmt, index, pBindStr, (strlen(pBindStr) + sizeof(unsigned char)), SQLITE_STATIC);
291 msg_error_t MsgDbHandler::bindInt(const int pBindint, int index)
295 ret = sqlite3_bind_int(stmt, index, pBindint);
301 msg_error_t MsgDbHandler::bindBlob(const void * pBindBlob, int size, int index)
305 ret = sqlite3_bind_blob(stmt, index, pBindBlob, size, SQLITE_STATIC);
311 msg_error_t MsgDbHandler::prepareQuery(const char *pQuery)
317 if(connect() != MSG_SUCCESS)
318 return MSG_ERR_DB_DISCONNECT;
320 ret = sqlite3_prepare_v2(handle, pQuery, strlen(pQuery), &stmt, NULL);
322 if (ret == SQLITE_BUSY) {
323 __clear_db_handle(handle);
324 ret = sqlite3_prepare_v2(handle, pQuery, strlen(pQuery), &stmt, NULL);
327 if (ret == SQLITE_OK) {
328 MSG_DEBUG("Prepare Query Success [%p]", stmt);
331 MSG_ERR("Prepare Query Fail [%d]", ret);
333 return MSG_ERR_DB_PREPARE;
340 msg_error_t MsgDbHandler::stepQuery()
344 MSG_DEBUG("stepQuery for [%p]", stmt);
345 ret = sqlite3_step(stmt);
347 if (ret == SQLITE_ROW) {
348 MSG_DEBUG("MsgStepQuery() SQLITE_ROW");
349 return MSG_ERR_DB_ROW;
350 } else if (ret == SQLITE_DONE) {
351 MSG_DEBUG("MsgStepQuery() SQLITE_DONE");
352 return MSG_ERR_DB_DONE;
354 MSG_ERR("MsgStepQuery() Fail [%d]", ret);
356 return MSG_ERR_DB_STEP;
363 void MsgDbHandler::resetQuery()
366 sqlite3_clear_bindings(stmt);
372 void MsgDbHandler::finalizeQuery()
376 int ret = sqlite3_finalize(stmt);
377 MSG_DEBUG("sqlite3_finalize = [%d]", ret);
379 __clear_db_handle(handle);
384 if (in_trans == false)
389 int MsgDbHandler::columnInt(int ColumnIndex)
391 return sqlite3_column_int(stmt, ColumnIndex);
395 const unsigned char* MsgDbHandler::columnText(int ColumnIndex)
397 return sqlite3_column_text(stmt, ColumnIndex);
401 const void* MsgDbHandler::columnBlob(int ColumnIndex)
403 return sqlite3_column_blob(stmt, ColumnIndex);
406 void MsgDbHandler::getMmapMutex(const char *shm_file_name)
411 MSG_FATAL("NULL INPUT_PARAM");
415 MSG_DEBUG("** mapping begin **");
417 /* open shm_file_name at first. Otherwise, the num of files in /proc/pid/fd will be increasing */
418 shm_fd = shm_open(shm_file_name, O_RDWR, 0);
420 MSG_FATAL("shm_open error [%d]", errno);
424 pthread_mutex_t *tmp = (pthread_mutex_t *)mmap(NULL, sizeof(pthread_mutex_t), PROT_READ|PROT_WRITE, MAP_SHARED, shm_fd, 0);
425 if (tmp == MAP_FAILED) {
426 MSG_FATAL("mmap error [%d]", errno);
432 void MsgDbHandler::shm_mutex_timedlock(int sec)
436 MSG_DEBUG("mmapMx not initd");
440 struct timespec abs_time;
441 clock_gettime(CLOCK_REALTIME, &abs_time);
442 abs_time.tv_sec += sec;
444 int err = pthread_mutex_timedlock(mmapMx, &abs_time);
446 if (err == EOWNERDEAD) {
447 err = pthread_mutex_consistent(mmapMx);
448 MSG_DEBUG("Previous owner is dead with lock. Fix mutex");
449 } else if (err != 0) {
450 MSG_FATAL("pthread_mutex_timedlock error [%d]", errno);
457 void MsgDbHandler::shm_mutex_unlock()
461 MSG_DEBUG("mmapMx not initd");
465 pthread_mutex_unlock(mmapMx);
469 msg_error_t MsgDbHandler::beginTrans()
473 if(connect() != MSG_SUCCESS)
474 return MSG_ERR_DB_DISCONNECT;
478 getMmapMutex(SHM_FILE_FOR_DB_LOCK);
480 shm_mutex_timedlock(2);
482 ret = sqlite3_exec(handle, "BEGIN IMMEDIATE TRANSACTION;", 0, 0, NULL);
484 if (ret == SQLITE_OK) {
485 MSG_DEBUG("Begin Transaction Success");
489 MSG_DEBUG("Begin Transaction Fail [%d]", ret);
490 return MSG_ERR_DB_EXEC;
497 msg_error_t MsgDbHandler::endTrans(bool Success)
501 if(connect() != MSG_SUCCESS)
502 return MSG_ERR_DB_DISCONNECT;
506 ret = sqlite3_exec(handle, "COMMIT TRANSACTION;", 0, 0, NULL);
508 ret = sqlite3_exec(handle, "ROLLBACK TRANSACTION;", 0, 0, NULL);
513 if (ret == SQLITE_OK) {
514 MSG_DEBUG("End Transaction Success");
519 MSG_DEBUG("End Transaction Fail [%d]", ret);
520 if (Success) endTrans(false);
521 return MSG_ERR_DB_EXEC;
528 int MsgDbHandler::getColumnToInt(int RowIndex)
530 char* pTemp = result[RowIndex];
538 nTemp = (int)strtol(pTemp, (char**)NULL, 10);
544 char MsgDbHandler::getColumnToChar(int RowIndex)
546 char* pTemp = result[RowIndex];
556 char *MsgDbHandler::getColumnToString(int RowIndex)
558 char* pTemp = result[RowIndex];
568 void MsgDbHandler::getColumnToString(int RowIndex, int Length, char *pString)
570 char* pTemp = result[RowIndex];
576 strncpy(pString, pTemp, Length);
580 msg_error_t MsgDbHandler::getRowId(const char *pTableName, unsigned int *pRowId)
582 int ret = 0, nRowId = 0, nRowCnt = 0;
585 if (pTableName == NULL || pRowId == NULL)
586 return MSG_ERR_INVALID_PARAMETER;
588 MSG_SEC_DEBUG("Table Name [%s]", pTableName);
590 memset(strQuery, 0x00, sizeof(strQuery));
591 snprintf(strQuery, sizeof(strQuery), "select max(rowid) from %s", pTableName);
593 ret = getTable(strQuery, &nRowCnt, NULL);
595 if (ret == SQLITE_OK) {
596 nRowId = getColumnToInt(1);
598 if ((nRowCnt <= 1) && (nRowId == 0))
601 *pRowId = nRowId + 1;
603 MSG_DEBUG("MsgGetRowId failed");
606 return MSG_ERR_DB_GETTABLE;
611 MSG_DEBUG("Row ID [%d]", *pRowId);
617 void MsgReleaseMemoryDB()
621 freeSize = sqlite3_release_memory(-1);
623 MSG_DEBUG("freed memory size (bytes) : [%d]", freeSize);
627 msg_error_t MsgConvertStrWithEscape(const char *input, char **output)
629 if (input == NULL || output == NULL || strlen(input) == 0) {
630 MSG_DEBUG("MSG_ERR_INVALID_PARAMETER");
631 return MSG_ERR_INVALID_PARAMETER;
638 inputSize = strlen(input);
639 MSG_DEBUG("Size of input string [%d]", inputSize);
641 char tmpStr[(inputSize*2)+3];
642 memset(tmpStr, 0x00, sizeof(tmpStr));
646 for(i = 0; i < inputSize; i++) {
647 if (input[i] == '\'' || input[i] == '_' || input[i] == '%' || input[i] == '\\') {
648 tmpStr[j++] = MSGFW_DB_ESCAPE_CHAR;
650 tmpStr[j++] = input[i];
655 *output = strdup(tmpStr);
660 typedef std::map<pthread_t, MsgDbHandler*> dbMap_t;
664 MsgDbHandler *getDbHandle()
666 pthread_t self = pthread_self();
667 MsgDbHandler *tmp = NULL;
669 dbMap_t::iterator it = gDbHandles.find(self);
670 if (it == gDbHandles.end()) {
671 MSG_DEBUG("New DB handle added.");
672 MsgMutexLocker locker(mu);
673 tmp = new MsgDbHandler();
674 gDbHandles.insert(std::pair<pthread_t, MsgDbHandler*>(self, tmp));
683 void removeDbHandle()
685 pthread_t self = pthread_self();
686 MsgDbHandler *tmp = NULL;
688 dbMap_t::iterator it = gDbHandles.find(self);
689 if (it != gDbHandles.end()) {
690 MsgMutexLocker locker(mu);
693 gDbHandles.erase(it);
698 static int __msg_db_util_busyhandler(void *pData, int count)
701 struct timespec time = {0, };
703 time.tv_nsec = (count + 1) * 50 * 1000 * 1000;
705 MSG_DEBUG("Busy Handler Called! : PID(%d) / CNT(%d)\n", getpid(), count+1);
706 nanosleep(&time, NULL);
709 MSG_WARN("Busy Handler will be returned SQLITE_BUSY error : PID(%d) \n", getpid());
714 int __msg_db_util_open(const char *pszFilePath, sqlite3 **ppDB, int flags, const char *zVfs)
716 if((pszFilePath == NULL) || (ppDB == NULL)) {
717 MSG_WARN("sqlite3 handle null error");
721 if((geteuid() != 0) && (access(pszFilePath, R_OK))) {
722 if(errno == EACCES) {
723 MSG_ERR("file access permission error");
729 int rc = sqlite3_open_v2(pszFilePath, ppDB, flags, zVfs);
730 if (SQLITE_OK != rc) {
731 MSG_ERR("sqlite3_open_v2 error(%d)", rc);
735 rc = sqlite3_busy_handler(*ppDB, __msg_db_util_busyhandler, NULL);
736 if (SQLITE_OK != rc) {
737 MSG_WARN("Fail to register busy handler\n");
738 sqlite3_close(*ppDB);
745 int __msg_db_util_close(sqlite3 *pDB)
748 MSG_WARN("sqlite3 handle null error");
753 int rc = sqlite3_close(pDB);
754 MSG_INFO("sqlite3_close error [%d]", rc);
756 if (rc == SQLITE_BUSY) {
757 __clear_db_handle(pDB);
758 rc = sqlite3_close(pDB);
761 if (SQLITE_OK != rc) {
762 MSG_ERR("sqlite3_close error [%d]", rc);
770 void __clear_db_handle(sqlite3 *pDB)
773 MSG_WARN("sqlite3 handle null error");
780 while ((pStmt = sqlite3_next_stmt(pDB, NULL)) != NULL) {
781 MSG_INFO("sqlite3_next_stmt [%s]", sqlite3_sql(pStmt));
782 rc = sqlite3_finalize(pStmt);
783 MSG_INFO("sqlite3_finalize [%d]", rc);