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");
451 MSG_FATAL("pthread_mutex_timedlock error [%d]", errno);
458 void MsgDbHandler::shm_mutex_unlock()
462 MSG_DEBUG("mmapMx not initd");
466 pthread_mutex_unlock(mmapMx);
470 msg_error_t MsgDbHandler::beginTrans()
474 if(connect() != MSG_SUCCESS)
475 return MSG_ERR_DB_DISCONNECT;
479 getMmapMutex(SHM_FILE_FOR_DB_LOCK);
481 shm_mutex_timedlock(2);
483 ret = sqlite3_exec(handle, "BEGIN IMMEDIATE TRANSACTION;", 0, 0, NULL);
485 if (ret == SQLITE_OK) {
486 MSG_DEBUG("Begin Transaction Success");
490 MSG_DEBUG("Begin Transaction Fail [%d]", ret);
491 return MSG_ERR_DB_EXEC;
498 msg_error_t MsgDbHandler::endTrans(bool Success)
502 if(connect() != MSG_SUCCESS)
503 return MSG_ERR_DB_DISCONNECT;
507 ret = sqlite3_exec(handle, "COMMIT TRANSACTION;", 0, 0, NULL);
509 ret = sqlite3_exec(handle, "ROLLBACK TRANSACTION;", 0, 0, NULL);
514 if (ret == SQLITE_OK) {
515 MSG_DEBUG("End Transaction Success");
520 MSG_DEBUG("End Transaction Fail [%d]", ret);
521 if (Success) endTrans(false);
522 return MSG_ERR_DB_EXEC;
529 int MsgDbHandler::getColumnToInt(int RowIndex)
531 char* pTemp = result[RowIndex];
539 nTemp = (int)strtol(pTemp, (char**)NULL, 10);
545 char MsgDbHandler::getColumnToChar(int RowIndex)
547 char* pTemp = result[RowIndex];
557 char *MsgDbHandler::getColumnToString(int RowIndex)
559 char* pTemp = result[RowIndex];
569 void MsgDbHandler::getColumnToString(int RowIndex, int Length, char *pString)
571 char* pTemp = result[RowIndex];
577 strncpy(pString, pTemp, Length);
581 msg_error_t MsgDbHandler::getRowId(const char *pTableName, unsigned int *pRowId)
583 int ret = 0, nRowId = 0, nRowCnt = 0;
586 if (pTableName == NULL || pRowId == NULL)
587 return MSG_ERR_INVALID_PARAMETER;
589 MSG_SEC_DEBUG("Table Name [%s]", pTableName);
591 memset(strQuery, 0x00, sizeof(strQuery));
592 snprintf(strQuery, sizeof(strQuery), "select max(rowid) from %s", pTableName);
594 ret = getTable(strQuery, &nRowCnt, NULL);
596 if (ret == SQLITE_OK) {
597 nRowId = getColumnToInt(1);
599 if ((nRowCnt <= 1) && (nRowId == 0))
602 *pRowId = nRowId + 1;
604 MSG_DEBUG("MsgGetRowId failed");
607 return MSG_ERR_DB_GETTABLE;
612 MSG_DEBUG("Row ID [%d]", *pRowId);
618 void MsgReleaseMemoryDB()
622 freeSize = sqlite3_release_memory(-1);
624 MSG_DEBUG("freed memory size (bytes) : [%d]", freeSize);
628 msg_error_t MsgConvertStrWithEscape(const char *input, char **output)
630 if (input == NULL || output == NULL || strlen(input) == 0) {
631 MSG_DEBUG("MSG_ERR_INVALID_PARAMETER");
632 return MSG_ERR_INVALID_PARAMETER;
639 inputSize = strlen(input);
640 MSG_DEBUG("Size of input string [%d]", inputSize);
642 char tmpStr[(inputSize*2)+3];
643 memset(tmpStr, 0x00, sizeof(tmpStr));
647 for(i = 0; i < inputSize; i++) {
648 if (input[i] == '\'' || input[i] == '_' || input[i] == '%' || input[i] == '\\') {
649 tmpStr[j++] = MSGFW_DB_ESCAPE_CHAR;
651 tmpStr[j++] = input[i];
656 *output = strdup(tmpStr);
661 typedef std::map<pthread_t, MsgDbHandler*> dbMap_t;
665 MsgDbHandler *getDbHandle()
667 pthread_t self = pthread_self();
668 MsgDbHandler *tmp = NULL;
670 dbMap_t::iterator it = gDbHandles.find(self);
671 if (it == gDbHandles.end()) {
672 MSG_DEBUG("New DB handle added.");
673 MutexLocker locker(mu);
674 tmp = new MsgDbHandler();
675 gDbHandles.insert(std::pair<pthread_t, MsgDbHandler*>(self, tmp));
684 void removeDbHandle()
686 pthread_t self = pthread_self();
687 MsgDbHandler *tmp = NULL;
689 dbMap_t::iterator it = gDbHandles.find(self);
690 if (it != gDbHandles.end()) {
691 MutexLocker locker(mu);
694 gDbHandles.erase(it);
699 static int __msg_db_util_busyhandler(void *pData, int count)
702 struct timespec time = {0, };
704 time.tv_nsec = (count + 1) * 50 * 1000 * 1000;
706 MSG_DEBUG("Busy Handler Called! : PID(%d) / CNT(%d)\n", getpid(), count+1);
707 nanosleep(&time, NULL);
710 MSG_WARN("Busy Handler will be returned SQLITE_BUSY error : PID(%d) \n", getpid());
715 int __msg_db_util_open(const char *pszFilePath, sqlite3 **ppDB, int flags, const char *zVfs)
717 if((pszFilePath == NULL) || (ppDB == NULL)) {
718 MSG_WARN("sqlite3 handle null error");
722 if((geteuid() != 0) && (access(pszFilePath, R_OK))) {
723 if(errno == EACCES) {
724 MSG_ERR("file access permission error");
730 int rc = sqlite3_open_v2(pszFilePath, ppDB, flags, zVfs);
731 if (SQLITE_OK != rc) {
732 MSG_ERR("sqlite3_open_v2 error(%d)", rc);
736 rc = sqlite3_busy_handler(*ppDB, __msg_db_util_busyhandler, NULL);
737 if (SQLITE_OK != rc) {
738 MSG_WARN("Fail to register busy handler\n");
739 sqlite3_close(*ppDB);
746 int __msg_db_util_close(sqlite3 *pDB)
749 MSG_WARN("sqlite3 handle null error");
754 int rc = sqlite3_close(pDB);
755 MSG_INFO("sqlite3_close error [%d]", rc);
757 if (rc == SQLITE_BUSY) {
758 __clear_db_handle(pDB);
759 rc = sqlite3_close(pDB);
762 if (SQLITE_OK != rc) {
763 MSG_ERR("sqlite3_close error [%d]", rc);
771 void __clear_db_handle(sqlite3 *pDB)
774 MSG_WARN("sqlite3 handle null error");
781 while ((pStmt = sqlite3_next_stmt(pDB, NULL)) != NULL) {
782 MSG_INFO("sqlite3_next_stmt [%s]", sqlite3_sql(pStmt));
783 rc = sqlite3_finalize(pStmt);
784 MSG_INFO("sqlite3_finalize [%d]", rc);