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);
84 return MSG_ERR_PERMISSION_DENIED;
86 MSG_DEBUG("DB Connect Fail [%d]", ret);
88 return MSG_ERR_DB_CONNECT;
91 MSG_DEBUG("DB Connect exist : [%p]", handle);
97 /* Use only in app side */
98 msg_error_t MsgDbHandler::connectReadOnly()
102 if (handle == NULL) {
105 memset(strDBName, 0x00, sizeof(strDBName));
106 snprintf(strDBName, 64, "%s", MSGFW_DB_NAME);
108 MSG_DEBUG("db_util_open_with_options SQLITE_OPEN_READONLY");
109 ret = __msg_db_util_open(strDBName, &handle, SQLITE_OPEN_READONLY, NULL);
111 if (ret == SQLITE_OK) {
112 MSG_DEBUG("DB Connect Success : [%p]", handle);
114 } else if (ret == SQLITE_PERM){
115 MSG_DEBUG("DB Connect Fail [%d]", ret);
116 return MSG_ERR_PERMISSION_DENIED;
118 MSG_DEBUG("DB Connect Fail [%d]", ret);
119 return MSG_ERR_DB_CONNECT;
122 MSG_DEBUG("DB Connect exist : [%p]", handle);
129 msg_error_t MsgDbHandler::disconnect()
133 if (handle != NULL) {
134 ret = __msg_db_util_close(handle);
136 if (ret == SQLITE_OK) {
138 MSG_DEBUG("DB Disconnect Success");
141 MSG_DEBUG("DB Disconnect Fail [%d]", ret);
142 return MSG_ERR_DB_DISCONNECT;
150 bool MsgDbHandler::checkTableExist(const char *pTableName)
153 int nRowCnt = 0, nResult = 0;
155 /* Formulate the Query */
156 memset(strQuery, 0x00, sizeof(strQuery));
157 snprintf(strQuery, sizeof(strQuery), "select count(name) from sqlite_master where name='%s'", pTableName);
159 if (getTable(strQuery, &nRowCnt, NULL) != MSG_SUCCESS) {
164 nResult = getColumnToInt(1);
165 MSG_DEBUG("Result [%d]", nResult);
176 msg_error_t MsgDbHandler::execQuery(const char *pQuery)
179 return MSG_ERR_INVALID_PARAMETER;
181 if(connect() != MSG_SUCCESS)
182 return MSG_ERR_DB_DISCONNECT;
184 if (prepareQuery(pQuery) != MSG_SUCCESS) {
185 MSG_DEBUG("Fail to prepareQuery.");
186 return MSG_ERR_DB_EXEC;
189 if (stepQuery() == MSG_ERR_DB_STEP) {
190 MSG_DEBUG("Fail to stepQuery.");
192 return MSG_ERR_DB_EXEC;
201 msg_error_t MsgDbHandler::getTable(const char *pQuery, int *pRowCnt, int *pColumnCnt)
209 if(connect() != MSG_SUCCESS)
210 return MSG_ERR_DB_DISCONNECT;
213 MSG_DEBUG("[%s]", pQuery);
214 ret = sqlite3_get_table(handle, pQuery, &result, pRowCnt, pColumnCnt, NULL);
216 if (ret == SQLITE_OK) {
217 if (*pRowCnt == 0) { /* when the no record return 'MSG_ERR_DB_NORECORD' */
218 MSG_DEBUG("No Query Result");
219 return MSG_ERR_DB_NORECORD;
222 MSG_DEBUG("Get Table Success");
224 } else if (ret == SQLITE_BUSY) {
225 MSG_DEBUG("The database file is locked [%d]", ret);
226 return MSG_ERR_DB_BUSY;
228 MSG_DEBUG("Get Table Fail [%d]", ret);
229 return MSG_ERR_DB_GETTABLE;
236 msg_error_t MsgDbHandler::getTableWithResult(const char *pQuery, char ***res, int *pRowCnt, int *pColumnCnt)
244 MSG_DEBUG("[%s]", pQuery);
245 ret = sqlite3_get_table(handle, pQuery, res, pRowCnt, pColumnCnt, NULL);
247 if (ret == SQLITE_OK) {
248 if (*pRowCnt == 0) { /* when the no record return 'MSG_ERR_DB_NORECORD' */
249 MSG_DEBUG("No Query Result");
250 return MSG_ERR_DB_NORECORD;
253 MSG_DEBUG("Get Table Success");
255 } else if (ret == SQLITE_BUSY) {
256 MSG_DEBUG("The database file is locked [%d]", ret);
257 return MSG_ERR_DB_BUSY;
259 MSG_DEBUG("Get Table Fail [%d]", ret);
260 return MSG_ERR_DB_GETTABLE;
266 void MsgDbHandler::freeTable()
269 sqlite3_free_table(result);
274 void MsgDbHandler::freeTable(char **db_res)
277 sqlite3_free_table(db_res);
282 msg_error_t MsgDbHandler::bindText(const char *pBindStr, int index)
286 if (pBindStr != NULL)
287 ret = sqlite3_bind_text(stmt, index, pBindStr, (strlen(pBindStr) + sizeof(unsigned char)), SQLITE_STATIC);
293 msg_error_t MsgDbHandler::bindInt(const int pBindint, int index)
297 ret = sqlite3_bind_int(stmt, index, pBindint);
303 msg_error_t MsgDbHandler::bindBlob(const void * pBindBlob, int size, int index)
307 ret = sqlite3_bind_blob(stmt, index, pBindBlob, size, SQLITE_STATIC);
313 msg_error_t MsgDbHandler::prepareQuery(const char *pQuery)
319 if(connect() != MSG_SUCCESS)
320 return MSG_ERR_DB_DISCONNECT;
322 ret = sqlite3_prepare_v2(handle, pQuery, strlen(pQuery), &stmt, NULL);
324 if (ret == SQLITE_BUSY) {
325 __clear_db_handle(handle);
326 ret = sqlite3_prepare_v2(handle, pQuery, strlen(pQuery), &stmt, NULL);
329 if (ret == SQLITE_OK) {
330 MSG_DEBUG("Prepare Query Success [%p]", stmt);
333 MSG_ERR("Prepare Query Fail [%d]", ret);
335 return MSG_ERR_DB_PREPARE;
342 msg_error_t MsgDbHandler::stepQuery()
346 MSG_DEBUG("stepQuery for [%p]", stmt);
347 ret = sqlite3_step(stmt);
349 if (ret == SQLITE_ROW) {
350 MSG_DEBUG("MsgStepQuery() SQLITE_ROW");
351 return MSG_ERR_DB_ROW;
352 } else if (ret == SQLITE_DONE) {
353 MSG_DEBUG("MsgStepQuery() SQLITE_DONE");
354 return MSG_ERR_DB_DONE;
356 MSG_ERR("MsgStepQuery() Fail [%d]", ret);
358 return MSG_ERR_DB_STEP;
365 void MsgDbHandler::resetQuery()
368 sqlite3_clear_bindings(stmt);
374 void MsgDbHandler::finalizeQuery()
378 int ret = sqlite3_finalize(stmt);
379 MSG_DEBUG("sqlite3_finalize = [%d]", ret);
381 __clear_db_handle(handle);
386 if (in_trans == false)
391 int MsgDbHandler::columnInt(int ColumnIndex)
393 return sqlite3_column_int(stmt, ColumnIndex);
397 const unsigned char* MsgDbHandler::columnText(int ColumnIndex)
399 return sqlite3_column_text(stmt, ColumnIndex);
403 const void* MsgDbHandler::columnBlob(int ColumnIndex)
405 return sqlite3_column_blob(stmt, ColumnIndex);
408 void MsgDbHandler::getMmapMutex(const char *shm_file_name)
413 MSG_FATAL("NULL INPUT_PARAM");
417 MSG_DEBUG("** mapping begin **");
419 /* open shm_file_name at first. Otherwise, the num of files in /proc/pid/fd will be increasing */
420 shm_fd = shm_open(shm_file_name, O_RDWR, 0);
422 MSG_FATAL("shm_open error [%d]", errno);
426 pthread_mutex_t *tmp = (pthread_mutex_t *)mmap(NULL, sizeof(pthread_mutex_t), PROT_READ|PROT_WRITE, MAP_SHARED, shm_fd, 0);
427 if (tmp == MAP_FAILED) {
428 MSG_FATAL("mmap error [%d]", errno);
434 void MsgDbHandler::shm_mutex_timedlock(int sec)
438 MSG_DEBUG("mmapMx not initd");
442 struct timespec abs_time;
443 clock_gettime(CLOCK_REALTIME, &abs_time);
444 abs_time.tv_sec += sec;
446 int err = pthread_mutex_timedlock(mmapMx, &abs_time);
448 if (err == EOWNERDEAD) {
449 err = pthread_mutex_consistent(mmapMx);
450 MSG_DEBUG("Previous owner is dead with lock. Fix mutex");
451 } else if (err != 0) {
452 MSG_FATAL("pthread_mutex_timedlock error [%d]", errno);
459 void MsgDbHandler::shm_mutex_unlock()
463 MSG_DEBUG("mmapMx not initd");
467 pthread_mutex_unlock(mmapMx);
471 msg_error_t MsgDbHandler::beginTrans()
475 if(connect() != MSG_SUCCESS)
476 return MSG_ERR_DB_DISCONNECT;
480 getMmapMutex(SHM_FILE_FOR_DB_LOCK);
482 shm_mutex_timedlock(2);
484 ret = sqlite3_exec(handle, "BEGIN IMMEDIATE TRANSACTION;", 0, 0, NULL);
486 if (ret == SQLITE_OK) {
487 MSG_DEBUG("Begin Transaction Success");
491 MSG_DEBUG("Begin Transaction Fail [%d]", ret);
492 return MSG_ERR_DB_EXEC;
499 msg_error_t MsgDbHandler::endTrans(bool Success)
503 if(connect() != MSG_SUCCESS)
504 return MSG_ERR_DB_DISCONNECT;
508 ret = sqlite3_exec(handle, "COMMIT TRANSACTION;", 0, 0, NULL);
510 ret = sqlite3_exec(handle, "ROLLBACK TRANSACTION;", 0, 0, NULL);
515 if (ret == SQLITE_OK) {
516 MSG_DEBUG("End Transaction Success");
521 MSG_DEBUG("End Transaction Fail [%d]", ret);
522 if (Success) endTrans(false);
523 return MSG_ERR_DB_EXEC;
530 int MsgDbHandler::getColumnToInt(int RowIndex)
532 char* pTemp = result[RowIndex];
540 nTemp = (int)strtol(pTemp, (char**)NULL, 10);
546 char MsgDbHandler::getColumnToChar(int RowIndex)
548 char* pTemp = result[RowIndex];
558 char *MsgDbHandler::getColumnToString(int RowIndex)
560 char* pTemp = result[RowIndex];
570 void MsgDbHandler::getColumnToString(int RowIndex, int Length, char *pString)
572 char* pTemp = result[RowIndex];
578 strncpy(pString, pTemp, Length);
582 msg_error_t MsgDbHandler::getRowId(const char *pTableName, unsigned int *pRowId)
584 int ret = 0, nRowId = 0, nRowCnt = 0;
587 if (pTableName == NULL || pRowId == NULL)
588 return MSG_ERR_INVALID_PARAMETER;
590 MSG_SEC_DEBUG("Table Name [%s]", pTableName);
592 memset(strQuery, 0x00, sizeof(strQuery));
593 snprintf(strQuery, sizeof(strQuery), "select max(rowid) from %s", pTableName);
595 ret = getTable(strQuery, &nRowCnt, NULL);
597 if (ret == SQLITE_OK) {
598 nRowId = getColumnToInt(1);
600 if ((nRowCnt <= 1) && (nRowId == 0))
603 *pRowId = nRowId + 1;
605 MSG_DEBUG("MsgGetRowId failed");
608 return MSG_ERR_DB_GETTABLE;
613 MSG_DEBUG("Row ID [%d]", *pRowId);
619 void MsgReleaseMemoryDB()
623 freeSize = sqlite3_release_memory(-1);
625 MSG_DEBUG("freed memory size (bytes) : [%d]", freeSize);
629 msg_error_t MsgConvertStrWithEscape(const char *input, char **output)
631 if (input == NULL || output == NULL || strlen(input) == 0) {
632 MSG_DEBUG("MSG_ERR_INVALID_PARAMETER");
633 return MSG_ERR_INVALID_PARAMETER;
640 inputSize = strlen(input);
641 MSG_DEBUG("Size of input string [%d]", inputSize);
643 char tmpStr[(inputSize*2)+3];
644 memset(tmpStr, 0x00, sizeof(tmpStr));
648 for(i = 0; i < inputSize; i++) {
649 if (input[i] == '\'' || input[i] == '_' || input[i] == '%' || input[i] == '\\') {
650 tmpStr[j++] = MSGFW_DB_ESCAPE_CHAR;
652 tmpStr[j++] = input[i];
657 *output = strdup(tmpStr);
662 typedef std::map<pthread_t, MsgDbHandler*> dbMap_t;
666 MsgDbHandler *getDbHandle()
668 pthread_t self = pthread_self();
669 MsgDbHandler *tmp = NULL;
671 dbMap_t::iterator it = gDbHandles.find(self);
672 if (it == gDbHandles.end()) {
673 MSG_DEBUG("New DB handle added.");
674 MsgMutexLocker locker(mu);
675 tmp = new MsgDbHandler();
676 gDbHandles.insert(std::pair<pthread_t, MsgDbHandler*>(self, tmp));
685 void removeDbHandle()
687 pthread_t self = pthread_self();
688 MsgDbHandler *tmp = NULL;
690 dbMap_t::iterator it = gDbHandles.find(self);
691 if (it != gDbHandles.end()) {
692 MsgMutexLocker locker(mu);
695 gDbHandles.erase(it);
700 static int __msg_db_util_busyhandler(void *pData, int count)
703 struct timespec time = {0, };
705 time.tv_nsec = (count + 1) * 50 * 1000 * 1000;
707 MSG_DEBUG("Busy Handler Called! : PID(%d) / CNT(%d)\n", getpid(), count+1);
708 nanosleep(&time, NULL);
711 MSG_WARN("Busy Handler will be returned SQLITE_BUSY error : PID(%d) \n", getpid());
716 int __msg_db_util_open(const char *pszFilePath, sqlite3 **ppDB, int flags, const char *zVfs)
718 if((pszFilePath == NULL) || (ppDB == NULL)) {
719 MSG_WARN("sqlite3 handle null error");
723 if((geteuid() != 0) && (access(pszFilePath, R_OK))) {
724 if(errno == EACCES) {
725 MSG_ERR("file access permission error");
731 int rc = sqlite3_open_v2(pszFilePath, ppDB, flags, zVfs);
732 if (SQLITE_OK != rc) {
733 MSG_ERR("sqlite3_open_v2 error(%d)", rc);
737 rc = sqlite3_busy_handler(*ppDB, __msg_db_util_busyhandler, NULL);
738 if (SQLITE_OK != rc) {
739 MSG_WARN("Fail to register busy handler\n");
740 sqlite3_close(*ppDB);
747 int __msg_db_util_close(sqlite3 *pDB)
750 MSG_WARN("sqlite3 handle null error");
755 int rc = sqlite3_close(pDB);
756 MSG_INFO("sqlite3_close error [%d]", rc);
758 if (rc == SQLITE_BUSY) {
759 __clear_db_handle(pDB);
760 rc = sqlite3_close(pDB);
763 if (SQLITE_OK != rc) {
764 MSG_ERR("sqlite3_close error [%d]", rc);
772 void __clear_db_handle(sqlite3 *pDB)
775 MSG_WARN("sqlite3 handle null error");
782 while ((pStmt = sqlite3_next_stmt(pDB, NULL)) != NULL) {
783 MSG_INFO("sqlite3_next_stmt [%s]", sqlite3_sql(pStmt));
784 rc = sqlite3_finalize(pStmt);
785 MSG_INFO("sqlite3_finalize [%d]", rc);