Add DBManager class 10/201710/9
authorjusung son <jusung07.son@samsung.com>
Tue, 19 Mar 2019 04:42:10 +0000 (13:42 +0900)
committerjusung son <jusung07.son@samsung.com>
Tue, 26 Mar 2019 06:15:44 +0000 (15:15 +0900)
Change-Id: I4ee8afc76194be7673592e164363a0909b655076
Signed-off-by: jusung son <jusung07.son@samsung.com>
notification-ex/db_manager.cc [new file with mode: 0644]
notification-ex/db_manager.h [new file with mode: 0644]

diff --git a/notification-ex/db_manager.cc b/notification-ex/db_manager.cc
new file mode 100644 (file)
index 0000000..10991fe
--- /dev/null
@@ -0,0 +1,774 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dlog.h>
+#include <unistd.h>
+#include <sqlite3.h>
+#include <vconf.h>
+#include <pkgmgr-info.h>
+#include <tzplatform_config.h>
+#include <string.h>
+#include <list>
+#include <map>
+
+#include "notification-ex/common.h"
+#include "notification-ex/db_manager.h"
+#include "notification-ex/item_inflator.h"
+#include "notification-ex/iitem_info_internal.h"
+#include "notification-ex/ex_util.h"
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "NOTIFICATION_EX"
+
+#define CREATE_NOTIFICATION_TABLE \
+  "PRAGMA journal_mode = PERSIST;\n" \
+  "PRAGMA synchronous = FULL;\n" \
+  "PRAGMA foreign_keys = ON;\n" \
+  "CREATE TABLE IF NOT EXISTS noti_ex_list (\n" \
+  " root_id TEXT NOT NULL,\n" \
+  " app_id TEXT NOT NULL,\n" \
+  " uid INTEGER,\n" \
+  " priv_id INTEGER,\n" \
+  " pkg_id TEXT,\n" \
+  " policy INTEGER,\n" \
+  " data TEXT NOT NULL,\n" \
+  " insert_time INTEGER,\n" \
+  " hide_list TEXT,\n" \
+  " PRIMARY KEY (root_id, app_id, uid));\n" \
+  "CREATE TABLE IF NOT EXISTS receiver_list (\n" \
+  " root_id TEXT NOT NULL,\n" \
+  " app_id TEXT NOT NULL,\n" \
+  " uid INTEGER,\n" \
+  " receiver_group TEXT NOT NULL,\n" \
+  " FOREIGN KEY (root_id, app_id, uid)\n" \
+  " REFERENCES noti_ex_list(root_id, app_id, uid) ON DELETE CASCADE);\n"
+
+#define DBPATH tzplatform_mkpath(TZ_SYS_DB, ".notification.db")
+#define NOTI_LIMIT 100
+
+using namespace std;
+using namespace notification::item;
+
+namespace notification {
+
+DBManager::DBManager() = default;
+DBManager::~DBManager() = default;
+
+sqlite3* DBManager::OpenDB() {
+  int ret;
+  sqlite3* db;
+
+  ret = sqlite3_open_v2(DBPATH, &db, SQLITE_OPEN_READWRITE, nullptr);
+  if (ret != SQLITE_OK) {
+    LOGE("open db(%s) error: %d", DBPATH, ret);
+    return nullptr;
+  }
+
+  return db;
+}
+
+void DBManager::CloseDB(sqlite3* db) {
+  int ret = SQLITE_OK;
+
+  if (db)
+    ret = sqlite3_close_v2(db);
+
+  if (ret != SQLITE_OK)
+    LOGE("close db error");
+}
+
+int DBManager::ExecuteQuery(sqlite3* db, const char* query, int* num_changes) {
+  int ret = NOTIFICATION_ERROR_NONE;
+  sqlite3_stmt *stmt;
+
+  if (db == nullptr || query == nullptr)
+    return NOTIFICATION_ERROR_INVALID_PARAMETER;
+
+  ret = sqlite3_prepare_v2(db, query, strlen(query), &stmt, nullptr);
+  if (ret != SQLITE_OK) {
+    /* LCOV_EXCL_START */
+    LOGE("Sqlite3 err[%d][%s]", ret, sqlite3_errmsg(db));
+    return NOTIFICATION_ERROR_FROM_DB;
+    /* LCOV_EXCL_STOP */
+  }
+
+  ret = sqlite3_step(stmt);
+  if (ret == SQLITE_OK || ret == SQLITE_DONE) {
+    if (num_changes != nullptr)
+    *num_changes = sqlite3_changes(db);
+    ret = NOTIFICATION_ERROR_NONE;
+  } else {
+    /* LCOV_EXCL_START */
+    LOGE("Sqlite err[%d][%s]", ret, sqlite3_errmsg(db));
+    ret = NOTIFICATION_ERROR_FROM_DB;
+    /* LCOV_EXCL_STOP */
+  }
+
+  sqlite3_finalize(stmt);
+  return ret;
+}
+
+int DBManager::ExecuteQuery(const char* query, int* num_changes) {
+  int ret;
+
+  if (query == nullptr)
+    return NOTIFICATION_ERROR_INVALID_PARAMETER;
+
+  sqlite3* db = OpenDB();
+  if (db == nullptr)
+    return NOTIFICATION_ERROR_FROM_DB;
+
+  ret = ExecuteQuery(db, query, num_changes);
+  CloseDB(db);
+
+  return ret;
+}
+
+int DBManager::CheckDBIntegrity(void* user_data, int argc,
+                                       char** argv, char** notUsed) {
+  bool* is_db_corrupted = static_cast<bool*>(user_data);
+
+  if (std::string(argv[0]).compare("ok")) {
+    LOGE("db integrity result : %s", argv[0]);
+    *is_db_corrupted = true;
+    return -1;
+  }
+
+  LOGI("db integrity result : %s", argv[0]);
+  return 0;
+}
+
+int DBManager::RecoverCorruptedDB(sqlite3* db) {
+  int ret = NOTIFICATION_ERROR_NONE;
+  char* errmsg = nullptr;
+
+  LOGI("DB is corrupted, start to recover corrupted db");
+  if (db)
+    sqlite3_close(db);
+  unlink(DBPATH);
+
+  ret = sqlite3_open_v2(DBPATH, &db,
+                        SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE, nullptr);
+  if (ret != SQLITE_OK) {
+    LOGE("Failed to open db[%d]", ret);
+    unlink(DBPATH);
+    ret = NOTIFICATION_ERROR_FROM_DB;
+    goto out;
+  }
+
+  ret = sqlite3_exec(db, CREATE_NOTIFICATION_TABLE, nullptr, nullptr, &errmsg);
+  if (ret != SQLITE_OK) {
+    LOGE("Failed to exec query[%d][%s]", ret, errmsg);
+    ret = NOTIFICATION_ERROR_FROM_DB;
+  }
+
+out:
+  if (errmsg)
+    sqlite3_free(errmsg);
+
+  return ret;
+}
+
+int DBManager::InitializeDB() {
+  int ret = NOTIFICATION_ERROR_NONE;
+  int sql_ret;
+  sqlite3* db;
+  char *errmsg = nullptr;
+  bool is_db_corrupted = false;
+
+  sql_ret = sqlite3_open_v2(DBPATH, &db,
+                 SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE, nullptr);
+  if (sql_ret != SQLITE_OK) {
+    LOGE("Failed to open db[%d]", ret);
+    ret = NOTIFICATION_ERROR_FROM_DB;
+    goto out;
+  }
+
+  sql_ret = sqlite3_exec(db, CREATE_NOTIFICATION_TABLE, nullptr, nullptr, &errmsg);
+  if (sql_ret != SQLITE_OK) {
+    LOGE("Failed to exec sqlite[%d][%s]", ret, errmsg);
+    ret = NOTIFICATION_ERROR_FROM_DB;
+    goto out;
+  }
+
+  sql_ret = sqlite3_exec(db, "PRAGMA foreign_keys = ON", NULL, NULL, NULL);
+  if (sql_ret != SQLITE_OK) {
+    LOGE("Failed to exec sqlite[%d][%s]", ret, errmsg);
+    ret = NOTIFICATION_ERROR_FROM_DB;
+    goto out;
+  }
+
+  sql_ret = sqlite3_exec(db, "PRAGMA integrity_check",
+              CheckDBIntegrity, &is_db_corrupted, &errmsg);
+  if (sql_ret != SQLITE_OK || is_db_corrupted) {
+    LOGE("Failed to exec query[%d][%s]", sql_ret, errmsg);
+    ret = NOTIFICATION_ERROR_FROM_DB;
+  }
+
+out:
+  if (sql_ret == SQLITE_CORRUPT || sql_ret == SQLITE_NOTADB || is_db_corrupted)
+    ret = RecoverCorruptedDB(db);
+  if (errmsg)
+    sqlite3_free(errmsg);
+  if (db)
+    sqlite3_close(db);
+
+  return ret;
+}
+
+void DBManager::InitializeData() {
+  char* query;
+
+  query = sqlite3_mprintf("DELETE FROM noti_ex_list WHERE policy & %d",
+  static_cast<int>(item::AbstractItem::Policy::OnBootClear));
+  if (!query) {
+    LOGE("OOM - sql query");
+    return;
+  }
+
+  ExecuteQuery(query, nullptr);
+  sqlite3_free(query);
+}
+
+void DBManager::CheckLimit(shared_ptr<item::AbstractItem> addedItem, sqlite3* db) {
+  int ret, count;
+  char* query;
+  sqlite3_stmt* stmt = nullptr;
+  sqlite3_stmt* delete_stmt = nullptr;
+  int uid = static_pointer_cast<IItemInfoInternal>(addedItem->GetInfo())->GetUid();
+
+  ret = GetCount(addedItem->GetSenderAppId(), uid, &count);
+  if (ret != NOTIFICATION_ERROR_NONE || count <= NOTI_LIMIT)
+    return;
+
+  query = sqlite3_mprintf("SELECT root_id FROM noti_ex_list WHERE uid = %d"
+                          " AND app_id = %Q ORDER BY insert_time ASC",
+                          uid, addedItem->GetSenderAppId().c_str());
+  if (query == nullptr) {
+    LOGE("OOM - sql query");
+    return;
+  }
+
+  ret = sqlite3_prepare_v2(db, query, -1, &stmt, nullptr);
+  if (ret != SQLITE_OK) {
+    /* LCOV_EXCL_START */
+    LOGE("sqlite3_prepare_v2 Failed [%d][%s]", ret, sqlite3_errmsg(db));
+    goto out;
+    /* LCOV_EXCL_STOP */
+  }
+
+  count -= NOTI_LIMIT;
+
+  sqlite3_free(query);
+  query = sqlite3_mprintf("DELETE FROM noti_ex_list"
+                          " WHERE root_id = ? AND app_id = %Q AND uid = %d",
+                          addedItem->GetSenderAppId().c_str(), uid);
+  if (query == nullptr) {
+    LOGE("OOM - sql query");
+    return;
+  }
+
+  ret = sqlite3_prepare_v2(db, query, -1, &delete_stmt, nullptr);
+  if (ret != SQLITE_OK) {
+    /* LCOV_EXCL_START */
+    LOGE("sqlite3_prepare_v2 Failed [%d][%s]", ret, sqlite3_errmsg(db));
+    goto out;
+    /* LCOV_EXCL_STOP */
+  }
+
+  while (sqlite3_step(stmt) == SQLITE_ROW && count > 0) {
+    ret = sqlite3_bind_text(delete_stmt, 1,
+            reinterpret_cast<const char *>(sqlite3_column_text(stmt, 0)),
+            -1, SQLITE_TRANSIENT);
+    if (ret != SQLITE_OK) {
+      LOGE("sqlite3_bind_int() error: %d(%s)", ret, sqlite3_errmsg(db));
+      goto out;
+    }
+
+    ret = sqlite3_step(delete_stmt);
+    if (ret != SQLITE_DONE) {
+      LOGE("step error: %d(%s)", ret, sqlite3_errmsg(db));
+      goto out;
+    }
+
+    ret = sqlite3_reset(delete_stmt);
+    if (ret != SQLITE_OK) {
+      LOGE("sqlite3_reset() error: %d", ret);
+      goto out;
+    }
+
+    sqlite3_clear_bindings(delete_stmt);
+
+    count--;
+  }
+
+out:
+  if (stmt)
+    sqlite3_finalize(stmt);
+  if (delete_stmt)
+    sqlite3_finalize(delete_stmt);
+  if (query)
+    sqlite3_free(query);
+}
+
+int DBManager::UpdateReceiverList
+    (shared_ptr<item::AbstractItem> updatedItem,  sqlite3* db) {
+  int ret;
+  char* query;
+  int uid = static_pointer_cast<IItemInfoInternal>(updatedItem->GetInfo())->GetUid();
+
+  query = sqlite3_mprintf("DELETE FROM receiver_list"
+            " WHERE root_id = %Q AND app_id = %Q AND uid = %d",
+            updatedItem->GetId().c_str(), updatedItem->GetSenderAppId().c_str(),
+            uid);
+  if (!query) {
+    LOGE("OOM - sql query");
+    return NOTIFICATION_ERROR_OUT_OF_MEMORY;
+  }
+
+  ret = ExecuteQuery(db, query, nullptr);
+  sqlite3_free(query);
+
+  if (ret != NOTIFICATION_ERROR_NONE)
+    return ret;
+
+  for (auto& i : updatedItem->GetReceiverList()) {
+    query = sqlite3_mprintf("INSERT INTO receiver_list"
+                            " (root_id, app_id, uid, receiver_group)"
+                            " VALUES (%Q, %Q, %d, %Q)",
+                            updatedItem->GetId().c_str(),
+                            updatedItem->GetSenderAppId().c_str(),
+                            uid,
+                            i.c_str());
+
+    if (!query) {
+      LOGE("OOM - sql query");
+      return NOTIFICATION_ERROR_OUT_OF_MEMORY;
+    }
+
+    ret = ExecuteQuery(db, query, nullptr);
+    sqlite3_free(query);
+
+    if (ret != NOTIFICATION_ERROR_NONE)
+      return ret;
+  }
+  return NOTIFICATION_ERROR_NONE;
+}
+
+int DBManager::InsertNotification(list<shared_ptr<item::AbstractItem>> addedItem) {
+  int ret, count;
+  char* query;
+  sqlite3* db = OpenDB();
+
+  if (db == nullptr)
+    return NOTIFICATION_ERROR_FROM_DB;
+
+  if (sqlite3_exec(db, "BEGIN TRANSACTION", nullptr, nullptr, nullptr)) {
+    LOGE("begin transaction error : %s", sqlite3_errmsg(db));
+    CloseDB(db);
+    return NOTIFICATION_ERROR_FROM_DB;
+  }
+
+  for (auto& i : addedItem) {
+    int uid = static_pointer_cast<IItemInfoInternal>(i->GetInfo())->GetUid();
+    ret = GetCount(i->GetId(), i->GetSenderAppId(), uid, &count);
+    if (ret != NOTIFICATION_ERROR_NONE)
+       break;
+
+    if (count > 0) {
+      LOGE("already exist id :[%s] appid[%s]",
+               i->GetId().c_str(), i->GetSenderAppId().c_str());
+      ret = NOTIFICATION_ERROR_ALREADY_EXIST_ID;
+      break;
+    }
+
+    Bundle b = i->Serialize();
+    query = sqlite3_mprintf("INSERT INTO noti_ex_list"
+          " (root_id, app_id, uid, priv_id, pkg_id, policy, data, insert_time)"
+          " VALUES (%Q, %Q, %d, %d, %Q, %d, %Q, %d)",
+          i->GetId().c_str(),
+          i->GetSenderAppId().c_str(),
+          uid,
+          util::GetQuarkFromString(i->GetId() + to_string(uid)),
+          GetPkgId(i->GetSenderAppId(),uid).c_str(),
+          static_cast<int>(i->GetPolicy()),
+          reinterpret_cast<char*>(b.ToRaw().first.get()),
+          static_pointer_cast<IItemInfo>(i->GetInfo())->GetTime());
+
+    if (!query) {
+      LOGE("OOM - sql query");
+      ret = NOTIFICATION_ERROR_OUT_OF_MEMORY;
+      break;
+    }
+
+    ret = ExecuteQuery(db, query, nullptr);
+    sqlite3_free(query);
+    if (ret != NOTIFICATION_ERROR_NONE)
+      break;
+
+    ret = UpdateReceiverList(i, db);
+    if (ret != NOTIFICATION_ERROR_NONE)
+      break;
+  }
+
+  if (ret == NOTIFICATION_ERROR_NONE) {
+    CheckLimit(*(addedItem.begin()), db);
+    if (sqlite3_exec(db, "END TRANSACTION", nullptr, nullptr, nullptr)) {
+      LOGE("end transaction error : %s", sqlite3_errmsg(db));
+      ret = NOTIFICATION_ERROR_FROM_DB;
+    }
+  } else {
+    if (sqlite3_exec(db, "ROLLBACK TRANSACTION", nullptr, nullptr, nullptr))
+    LOGE("rollback transaction error : %s", sqlite3_errmsg(db));
+  }
+
+  CloseDB(db);
+  return ret;
+}
+
+map<string, string> DBManager::GetHideMap() {
+  map<string, string> hide_map;
+  char* query;
+  sqlite3_stmt* stmt;
+  sqlite3* db;
+  int ret;
+  string key;
+
+  query = sqlite3_mprintf("SELECT root_id, app_id, uid, hide_list FROM noti_ex_list"
+                            " WHERE hide_list IS NOT NULL");
+  if (!query) {
+    LOGE("OOM - sql query");
+    return hide_map;
+  }
+
+  db = OpenDB();
+  if (db == nullptr) {
+    sqlite3_free(query);
+    return hide_map;
+  }
+
+  ret = sqlite3_prepare_v2(db, query, strlen(query), &stmt, nullptr);
+  if (ret != SQLITE_OK) {
+    LOGE("Failed to sqlite3_prepare [%d][%s]", ret,    sqlite3_errmsg(db));
+    CloseDB(db);
+    sqlite3_free(query);
+    return hide_map;
+  }
+  sqlite3_free(query);
+
+  while (sqlite3_step(stmt) == SQLITE_ROW) {
+    key = string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0))) \
+          + string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1))) \
+          + string(to_string(sqlite3_column_int(stmt, 2)));
+    hide_map[key] = string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 3)));
+  }
+
+  sqlite3_finalize(stmt);
+  CloseDB(db);
+  return hide_map;
+}
+
+int DBManager::GetCount(const string& app_id, int uid, int* count) {
+  return GetCount(string(), app_id, uid, count);
+}
+
+int DBManager::GetCount(const string& root_id, const string& app_id,
+                              int uid, int* count) {
+  int ret;
+  char* query;
+  sqlite3_stmt *stmt;
+  sqlite3* db;
+
+  if (root_id.empty()) {
+    query = sqlite3_mprintf("SELECT count(*) FROM noti_ex_list"
+                            " WHERE app_id = %Q AND uid = %d", app_id.c_str(), uid);
+  } else {
+    query = sqlite3_mprintf("SELECT count(*) FROM noti_ex_list"
+                            " WHERE root_id = %Q AND app_id = %Q AND uid = %d",
+                            root_id.c_str(), app_id.c_str(), uid);
+  }
+  if (!query) {
+    LOGE("OOM - sql query");
+    return NOTIFICATION_ERROR_OUT_OF_MEMORY;
+  }
+
+  db = OpenDB();
+  if (db == nullptr) {
+    sqlite3_free(query);
+    return NOTIFICATION_ERROR_FROM_DB;
+  }
+
+  ret = sqlite3_prepare_v2(db, query, strlen(query), &stmt, nullptr);
+  if (ret != SQLITE_OK) {
+    LOGE("Failed to sqlite3_prepare [%d][%s]", ret,    sqlite3_errmsg(db));
+    sqlite3_free(query);
+    CloseDB(db);
+    return NOTIFICATION_ERROR_FROM_DB;
+  }
+  sqlite3_free(query);
+
+  ret = sqlite3_step(stmt);
+  if (ret == SQLITE_ROW)
+    *count = sqlite3_column_int(stmt, 0);
+  else
+    *count = 0;
+
+  sqlite3_finalize(stmt);
+  CloseDB(db);
+  return NOTIFICATION_ERROR_NONE;
+}
+
+int DBManager::UpdateHideList(shared_ptr<item::AbstractItem> updatedItem,
+    const string& hide_list) {
+  int ret;
+  char* query;
+
+  query = sqlite3_mprintf("UPDATE noti_ex_list SET hide_list = %Q"
+            " WHERE root_id = %Q AND app_id = %Q AND uid = %d",
+            hide_list.c_str(), updatedItem->GetId().c_str(),
+            updatedItem->GetSenderAppId().c_str(),
+            static_pointer_cast<IItemInfoInternal>(updatedItem->GetInfo())->GetUid());
+  if (!query) {
+    LOGE("OOM - sql query");
+    return NOTIFICATION_ERROR_OUT_OF_MEMORY;
+  }
+
+  ret = ExecuteQuery(query, nullptr);
+  sqlite3_free(query);
+
+  return ret;
+}
+
+int DBManager::UpdateNotification(shared_ptr<item::AbstractItem> updatedItem) {
+  int count, ret;
+  char* query;
+  int uid = static_pointer_cast<IItemInfoInternal>(updatedItem->GetInfo())->GetUid();
+
+  ret = GetCount(updatedItem->GetId(), updatedItem->GetSenderAppId(), uid, &count);
+  if (ret != NOTIFICATION_ERROR_NONE)
+    return ret;
+
+  if (count <= 0)
+    return NOTIFICATION_ERROR_NOT_EXIST_ID;
+
+  sqlite3* db = OpenDB();
+  if (db == nullptr)
+    return NOTIFICATION_ERROR_FROM_DB;
+
+  Bundle b = updatedItem->Serialize();
+  query = sqlite3_mprintf("UPDATE noti_ex_list SET"
+     " priv_id = %d, pkg_id = %Q, policy = %d, data = %Q, insert_time = %d"
+     " WHERE root_id = %Q AND app_id = %Q AND uid = %d",
+     util::GetQuarkFromString(updatedItem->GetId() + to_string(uid)),
+     GetPkgId(updatedItem->GetSenderAppId(), uid).c_str(),
+     static_cast<int>(updatedItem->GetPolicy()),
+     reinterpret_cast<char*>(b.ToRaw().first.get()),
+     static_pointer_cast<IItemInfo>(updatedItem->GetInfo())->GetTime(),
+     updatedItem->GetId().c_str(),
+     updatedItem->GetSenderAppId().c_str(),
+     uid);
+
+  if (!query) {
+    LOGE("OOM - sql query");
+    CloseDB(db);
+    return NOTIFICATION_ERROR_OUT_OF_MEMORY;
+  }
+
+  if (sqlite3_exec(db, "BEGIN TRANSACTION", nullptr, nullptr, nullptr)) {
+    LOGE("begin transaction error : %s", sqlite3_errmsg(db));
+    sqlite3_free(query);
+    CloseDB(db);
+    return NOTIFICATION_ERROR_FROM_DB;
+  }
+
+  ret = ExecuteQuery(db, query, nullptr);
+  sqlite3_free(query);
+  if (ret != NOTIFICATION_ERROR_NONE)
+    goto out;
+
+  ret = UpdateReceiverList(updatedItem, db);
+
+out:
+  if (ret == NOTIFICATION_ERROR_NONE) {
+    if (sqlite3_exec(db, "END TRANSACTION", nullptr, nullptr, nullptr)) {
+      LOGE("end transaction error : %s", sqlite3_errmsg(db));
+      ret = NOTIFICATION_ERROR_FROM_DB;
+    }
+  } else {
+    if (sqlite3_exec(db, "ROLLBACK TRANSACTION", nullptr, nullptr, nullptr))
+    LOGE("rollback transaction error : %s", sqlite3_errmsg(db));
+  }
+
+  CloseDB(db);
+  return ret;
+}
+
+list<shared_ptr<item::AbstractItem>> DBManager::ExecuteGetList(char* query) {
+  sqlite3_stmt *stmt;
+  sqlite3* db;
+  int ret;
+  list<shared_ptr<item::AbstractItem>> item_list;
+
+  if (!query) {
+    LOGE("Invalid parameter");
+    return item_list;
+  }
+
+  db = OpenDB();
+  if (db == nullptr)
+    return item_list;
+
+  ret = sqlite3_prepare_v2(db, query, strlen(query), &stmt, nullptr);
+  if (ret != SQLITE_OK) {
+    LOGE("Failed to sqlite3_prepare [%d][%s]", ret, sqlite3_errmsg(db));
+    CloseDB(db);
+    return item_list;
+  }
+
+  while (sqlite3_step(stmt) == SQLITE_ROW) {
+    LOGE("[%s]", sqlite3_column_text(stmt, 0));
+
+    Bundle serialized(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0)));
+    shared_ptr<item::AbstractItem> gen_item = item::ItemInflator::Create(serialized);
+    item_list.emplace_back(gen_item);
+  }
+
+  sqlite3_finalize(stmt);
+  CloseDB(db);
+  return item_list;
+}
+
+list<shared_ptr<item::AbstractItem>> DBManager::GetNotificationList(string app_id, int uid) {
+  char* query;
+  list<shared_ptr<item::AbstractItem>> item_list;
+
+  query = sqlite3_mprintf("SELECT data FROM noti_ex_list"
+                    " WHERE uid = %d AND app_id = %Q ORDER BY insert_time DESC",
+                    uid, app_id.c_str());
+  if (!query) {
+    LOGE("OOM - sql query");
+    return item_list;
+  }
+
+  item_list = ExecuteGetList(query);
+  sqlite3_free(query);
+
+  return item_list;
+}
+
+list<shared_ptr<item::AbstractItem>> DBManager::GetNotificationList
+                             (string app_id, string root_id, int uid) {
+  char* query;
+  list<shared_ptr<item::AbstractItem>> item_list;
+
+  query = sqlite3_mprintf("SELECT data FROM noti_ex_list"
+                           " WHERE uid = %d AND app_id = %Q AND root_id = %Q",
+                           uid, app_id.c_str(), root_id.c_str());
+
+  if (!query) {
+    LOGE("OOM - sql query");
+    return item_list;
+  }
+
+  item_list = ExecuteGetList(query);
+  sqlite3_free(query);
+
+  return item_list;
+}
+
+list<shared_ptr<item::AbstractItem>> DBManager::GetNotificationList(int uid) {
+  int ret, sim_mode;
+  char* query;
+  list<shared_ptr<item::AbstractItem>> item_list;
+
+  /* Check current sim status */
+  ret = vconf_get_int(VCONFKEY_TELEPHONY_SIM_SLOT, &sim_mode);
+  if (ret < 0) {
+    sim_mode = VCONFKEY_TELEPHONY_SIM_INSERTED;
+    LOGI("vconf_get_int");
+  }
+
+  if (sim_mode == VCONFKEY_TELEPHONY_SIM_INSERTED) {
+    query = sqlite3_mprintf("SELECT data FROM noti_ex_list WHERE uid = %d"
+                            " ORDER BY insert_time DESC", uid);
+  } else {
+    query = sqlite3_mprintf("SELECT data FROM noti_ex_list"
+            " WHERE  uid = %d AND (policy & %d) != 0 ORDER BY insert_time DESC",
+            uid, static_cast<int>(item::AbstractItem::Policy::SimMode));
+  }
+
+  if (!query) {
+    LOGE("OOM - sql query");
+    return item_list;
+  }
+
+  item_list = ExecuteGetList(query);
+  sqlite3_free(query);
+
+  return item_list;
+}
+
+int DBManager::DeleteNotification(shared_ptr<item::AbstractItem> deletedItem) {
+  int ret;
+  char* query;
+  int uid = static_pointer_cast<IItemInfoInternal>(deletedItem->GetInfo())->GetUid();
+
+  query = sqlite3_mprintf("DELETE FROM noti_ex_list"
+            " WHERE root_id = %Q AND app_id = %Q AND uid = %d",
+            deletedItem->GetId().c_str(), deletedItem->GetSenderAppId().c_str(),
+            uid);
+  if (!query) {
+    LOGE("OOM - sql query");
+    return NOTIFICATION_ERROR_OUT_OF_MEMORY;
+  }
+
+  ret = ExecuteQuery(query, nullptr);
+  sqlite3_free(query);
+  if (ret != NOTIFICATION_ERROR_NONE)
+    return ret;
+
+  query = sqlite3_mprintf("DELETE FROM receiver_list"
+                " WHERE root_id = %Q AND app_id = %Q AND uid = %d",
+                deletedItem->GetId().c_str(), deletedItem->GetSenderAppId().c_str(),
+                uid);
+  if (!query) {
+    LOGE("OOM - sql query");
+    return NOTIFICATION_ERROR_OUT_OF_MEMORY;
+  }
+
+  ret = ExecuteQuery(query, nullptr);
+  sqlite3_free(query);
+
+  return ret;
+}
+
+string DBManager::GetPkgId(const string& app_id, int uid) {
+  pkgmgrinfo_pkginfo_h handle;
+  char *buf = nullptr;
+  string pkgid;
+
+  if (pkgmgrinfo_appinfo_get_usr_appinfo(app_id.c_str(), uid, &handle) == PMINFO_R_OK) {
+    if (pkgmgrinfo_appinfo_get_pkgid(handle, &buf) == PMINFO_R_OK) {
+      if (buf)
+        pkgid = string(buf);
+    }
+    pkgmgrinfo_appinfo_destroy_appinfo(handle);
+  }
+  return pkgid;
+}
+}  // namespace notification
diff --git a/notification-ex/db_manager.h b/notification-ex/db_manager.h
new file mode 100644 (file)
index 0000000..23f6346
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef NOTIFICATION_EX_DB_MANAGER_H_
+#define NOTIFICATION_EX_DB_MANAGER_H_
+
+#include <sqlite3.h>
+
+#include <string>
+#include <memory>
+#include <map>
+#include <list>
+
+#include "notification-ex/abstract_item.h"
+
+#ifndef EXPORT_API
+#define EXPORT_API __attribute__((visibility("default")))
+#endif
+
+namespace notification {
+
+class EXPORT_API DBManager {
+ public:
+  static int InitializeDB();
+  static void InitializeData();
+  static int InsertNotification(std::list<std::shared_ptr<item::AbstractItem>> addedItem);
+  static std::map<std::string, std::string> GetHideMap();
+  static int UpdateHideList(std::shared_ptr<item::AbstractItem> updatedItem, const std::string& hide_list);
+  static int UpdateNotification(std::shared_ptr<item::AbstractItem> updatedItem);
+  static int GetCount(const std::string& root_id, const std::string& app_id, int uid, int* count);
+  static int GetCount(const std::string& app_id, int uid, int* count);
+  static int DeleteNotification(std::shared_ptr<item::AbstractItem> deletedItem);
+  static std::list<std::shared_ptr<item::AbstractItem>> GetNotificationList(int uid);
+  static std::list<std::shared_ptr<item::AbstractItem>> GetNotificationList(std::string app_id, int uid);
+  static std::list<std::shared_ptr<item::AbstractItem>> GetNotificationList(std::string app_id, std::string root_id, int uid);
+
+ private:
+  DBManager(); /* LCOV_EXCL_LINE */
+  ~DBManager(); /* LCOV_EXCL_LINE */
+  static sqlite3* OpenDB();
+  static void CloseDB(sqlite3* db);
+  static int CheckDBIntegrity(void* user_data, int argc, char** argv, char** notUsed);
+  static int RecoverCorruptedDB(sqlite3* db);
+  static int ExecuteQuery(const char* query, int* num_changes);
+  static int ExecuteQuery(sqlite3* db, const char* query, int* num_changes);
+  static std::string GetPkgId(const std::string& app_id, int uid);
+  static void CheckLimit(std::shared_ptr<item::AbstractItem> addedItem, sqlite3* db);
+  static int UpdateReceiverList(std::shared_ptr<item::AbstractItem> updatedItem,  sqlite3* db);
+  static std::list<std::shared_ptr<item::AbstractItem>> ExecuteGetList(char* query);
+
+};
+}  // namespace notification
+
+#endif  // NOTIFICATION_EX_DB_MANAGER_H_
\ No newline at end of file