Implement AppDB by sqlite 25/44725/4
authorSeungkeun Lee <sngn.lee@samsung.com>
Mon, 27 Jul 2015 06:45:38 +0000 (15:45 +0900)
committerSeungkeun Lee <sngn.lee@samsung.com>
Wed, 29 Jul 2015 05:03:11 +0000 (22:03 -0700)
Change-Id: If38d54e4c8fbc531570f00557521c9810a103bc9

packaging/wrt.spec
src/common/CMakeLists.txt
src/common/app_db.cc
src/common/app_db_sqlite.h [new file with mode: 0755]
tests/utc/common/CMakeLists.txt
tests/utc/common/utc_appdb_sqlite.cc [new file with mode: 0755]

index 04bafed..791be75 100755 (executable)
@@ -38,6 +38,7 @@ BuildRequires: pkgconfig(gio-2.0)
 BuildRequires: pkgconfig(aul)
 BuildRequires: pkgconfig(ecore)
 BuildRequires: pkgconfig(notification)
+BuildRequires: pkgconfig(sqlite3)
 BuildRequires: boost-devel
 BuildRequires: python
 %if %{with x}
index b2e073c..778d765 100755 (executable)
@@ -25,6 +25,7 @@ PKG_CHECK_MODULES(TARGET_COMMON_STATIC_DEPS
   appsvc
   manifest-parser
   manifest-handlers
+  sqlite3
   REQUIRED
 )
 
index b9ff08e..f2087de 100755 (executable)
 
 #include "common/app_db.h"
 
-#include <app_preference.h>
+//  #define USE_APP_PREFERENCE;
+#ifdef USE_APP_PREFERENCE
+  #include <app_preference.h>
+#else
+  #include "common/app_db_sqlite.h"
+
+  #include <unistd.h>
+  #include <sqlite3.h>
+  #include <app.h>
+#endif
+
 #include <memory>
 
 #include "common/string_utils.h"
+#include "common/logger.h"
 
 namespace wrt {
 
 namespace {
+#ifdef USE_APP_PREFERENCE
   const char* kSectionPrefix = "_SECT_";
   const char* kSectionSuffix = "_SECT_";
+#else
+  const char* kCreateDbQuery = "CREATE TABLE IF NOT EXISTS appdb ("
+                               "section TEXT, "
+                               "key TEXT, "
+                               "value TEXT,"
+                               "PRIMARY KEY(section, key));";
+#endif
 
 }  // namespace
 
+#ifdef USE_APP_PREFERENCE
+
 class PreferenceAppDB : public AppDB {
  public:
   PreferenceAppDB();
@@ -94,9 +115,261 @@ void PreferenceAppDB::Remove(const std::string& section,
   preference_remove(combined_key.c_str());
 }
 
+#else  // end of USE_APP_PREFERENCE
+
+SqliteDB::SqliteDB(const std::string& app_data_path)
+    : app_data_path_(app_data_path),
+      sqldb_(NULL) {
+  if (app_data_path_.empty()) {
+    std::unique_ptr<char, decltype(std::free)*>
+    path {app_get_data_path(), std::free};
+    if (path.get() != NULL)
+      app_data_path_ = path.get();
+  }
+  Initialize();
+}
+
+SqliteDB::~SqliteDB() {
+  if (sqldb_ != NULL) {
+    sqlite3_close(sqldb_);
+    sqldb_ = NULL;
+  }
+}
+
+void SqliteDB::Initialize() {
+  if (app_data_path_.empty()) {
+    LOGGER(ERROR) << "app data path was empty";
+    return;
+  }
+  std::string db_path = app_data_path_ + "/.appdb.db";
+  int ret = sqlite3_open(db_path.c_str(), &sqldb_);
+  if (ret != SQLITE_OK) {
+    LOGGER(ERROR) << "Fail to open app db :" << sqlite3_errmsg(sqldb_);
+    sqldb_ = NULL;
+    return;
+  }
+  sqlite3_busy_handler(sqldb_, [](void *, int count) {
+    if (count < 5) {
+      LOGGER(ERROR) << "App db was busy, Wait the lock count(" << count << ")";
+      usleep(100000*(count+1));
+      return 1;
+    } else {
+      LOGGER(ERROR) << "App db was busy, Fail to access";
+      return 0;
+    }
+  }, NULL);
+
+  char *errmsg = NULL;
+  ret = sqlite3_exec(sqldb_, kCreateDbQuery, NULL, NULL, &errmsg);
+  if (ret != SQLITE_OK) {
+    LOGGER(ERROR) << "Error to create appdb : " << (errmsg ? errmsg : "");
+    if (errmsg)
+      sqlite3_free(errmsg);
+  }
+}
+
+bool SqliteDB::HasKey(const std::string& section,
+                      const std::string& key) const {
+  char *buffer = NULL;
+  sqlite3_stmt *stmt = NULL;
+  bool result = false;
+
+  int ret = 0;
+  buffer = sqlite3_mprintf(
+      "select count(*) from appdb where section = %Q and key = %Q",
+      section.c_str(),
+      key.c_str());
+  if (buffer == NULL) {
+    LOGGER(ERROR) << "error to make query";
+    return false;
+  }
+
+  std::unique_ptr<char, decltype(sqlite3_free)*>
+      scoped_data {buffer, sqlite3_free};
+
+  ret = sqlite3_prepare(sqldb_, buffer, strlen(buffer), &stmt, NULL);
+  if (ret != SQLITE_OK) {
+    LOGGER(ERROR) << "Fail to prepare query : " << sqlite3_errmsg(sqldb_);
+    return false;
+  }
+
+  ret = sqlite3_step(stmt);
+  if (ret == SQLITE_ROW) {
+    int value = sqlite3_column_int(stmt, 0);
+    result = value > 0;
+  }
+
+  sqlite3_finalize(stmt);
+  return result;
+}
+
+std::string SqliteDB::Get(const std::string& section,
+                          const std::string& key) const {
+  char *buffer = NULL;
+  sqlite3_stmt *stmt = NULL;
+  std::string result;
+
+  int ret = 0;
+  buffer = sqlite3_mprintf(
+      "select value from appdb where section = %Q and key = %Q",
+      section.c_str(),
+      key.c_str());
+  if (buffer == NULL) {
+    LOGGER(ERROR) << "error to make query";
+    return result;
+  }
+
+  std::unique_ptr<char, decltype(sqlite3_free)*>
+      scoped_data {buffer, sqlite3_free};
+
+  ret = sqlite3_prepare(sqldb_, buffer, strlen(buffer), &stmt, NULL);
+  if (ret != SQLITE_OK) {
+    LOGGER(ERROR) << "Fail to prepare query : " << sqlite3_errmsg(sqldb_);
+    return result;
+  }
+
+  ret = sqlite3_step(stmt);
+  if (ret == SQLITE_ROW) {
+    result = std::string(
+        reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0)));
+  }
+
+  sqlite3_finalize(stmt);
+  return result;
+}
+
+void SqliteDB::Set(const std::string& section,
+                   const std::string& key,
+                   const std::string& value) {
+  char *buffer = NULL;
+  sqlite3_stmt *stmt = NULL;
+
+  int ret = 0;
+  buffer = sqlite3_mprintf(
+      "replace into appdb (section, key, value) values (?, ?, ?);");
+  if (buffer == NULL) {
+    LOGGER(ERROR) << "error to make query";
+    return;
+  }
+
+  std::unique_ptr<char, decltype(sqlite3_free)*>
+      scoped_data {buffer, sqlite3_free};
+
+  ret = sqlite3_prepare(sqldb_, buffer, strlen(buffer), &stmt, NULL);
+  if (ret != SQLITE_OK) {
+    LOGGER(ERROR) << "Fail to prepare query : " << sqlite3_errmsg(sqldb_);
+    return;
+  }
+
+  std::unique_ptr<sqlite3_stmt, decltype(sqlite3_finalize)*>
+      scoped_stmt {stmt, sqlite3_finalize};
+
+  ret = sqlite3_bind_text(stmt,
+                          1,
+                          section.c_str(),
+                          section.length(),
+                          SQLITE_STATIC);
+  if (ret != SQLITE_OK) {
+    LOGGER(ERROR) << "Fail to prepare query bind argument : "
+                  << sqlite3_errmsg(sqldb_);
+    return;
+  }
+  ret = sqlite3_bind_text(stmt,
+                          2,
+                          key.c_str(),
+                          key.length(),
+                          SQLITE_STATIC);
+  if (ret != SQLITE_OK) {
+    LOGGER(ERROR) << "Fail to prepare query bind argument : "
+                  << sqlite3_errmsg(sqldb_);
+    return;
+  }
+  ret = sqlite3_bind_text(stmt,
+                          3,
+                          value.c_str(),
+                          value.length(),
+                          SQLITE_STATIC);
+  if (ret != SQLITE_OK) {
+    LOGGER(ERROR) << "Fail to prepare query bind argument : "
+                  << sqlite3_errmsg(sqldb_);
+    return;
+  }
+  ret = sqlite3_step(stmt);
+  if (ret != SQLITE_DONE) {
+    LOGGER(ERROR) << "Fail to insert data : " << sqlite3_errmsg(sqldb_);
+  }
+}
+
+void SqliteDB::Remove(const std::string& section,
+                      const std::string& key) {
+  char *buffer = NULL;
+  sqlite3_stmt *stmt = NULL;
+
+  buffer = sqlite3_mprintf(
+      "delete from appdb where section = %Q and key = %Q",
+      section.c_str(),
+      key.c_str());
+
+  if (buffer == NULL) {
+    LOGGER(ERROR) << "error to make query";
+    return;
+  }
+
+  std::unique_ptr<char, decltype(sqlite3_free)*>
+      scoped_data {buffer, sqlite3_free};
+
+  char *errmsg = NULL;
+  int ret = sqlite3_exec(sqldb_, buffer, NULL, NULL, &errmsg);
+  if (ret != SQLITE_OK) {
+    LOGGER(ERROR) << "Error to delete value : " << (errmsg ? errmsg : "");
+    if (errmsg)
+      sqlite3_free(errmsg);
+  }
+}
+
+void SqliteDB::GetKeys(const std::string& section,
+                       std::list<std::string>* keys) const {
+  char *buffer = NULL;
+  sqlite3_stmt *stmt = NULL;
+
+  int ret = 0;
+  buffer = sqlite3_mprintf(
+      "select key from appdb where section = %Q",
+      section.c_str());
+  if (buffer == NULL) {
+    LOGGER(ERROR) << "error to make query";
+    return;
+  }
+
+  std::unique_ptr<char, decltype(sqlite3_free)*>
+      scoped_data {buffer, sqlite3_free};
+
+  ret = sqlite3_prepare(sqldb_, buffer, strlen(buffer), &stmt, NULL);
+  if (ret != SQLITE_OK) {
+    LOGGER(ERROR) << "Fail to prepare query : " << sqlite3_errmsg(sqldb_);
+    return;
+  }
+
+  ret = sqlite3_step(stmt);
+  while (ret == SQLITE_ROW) {
+    const char* value =
+        reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0));
+    keys->push_back(std::string(value));
+    ret = sqlite3_step(stmt);
+  }
+
+  sqlite3_finalize(stmt);
+  return;
+}
+
+#endif  // end of else
 
 AppDB* AppDB::GetInstance() {
+#ifdef USE_APP_PREFERENCE
   static PreferenceAppDB instance;
+#else
+  static SqliteDB instance;
+#endif
   return &instance;
 }
 
diff --git a/src/common/app_db_sqlite.h b/src/common/app_db_sqlite.h
new file mode 100755 (executable)
index 0000000..8c10e16
--- /dev/null
@@ -0,0 +1,47 @@
+/*\r
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved\r
+ *\r
+ *    Licensed under the Apache License, Version 2.0 (the "License");\r
+ *    you may not use this file except in compliance with the License.\r
+ *    You may obtain a copy of the License at\r
+ *\r
+ *        http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ *    Unless required by applicable law or agreed to in writing, software\r
+ *    distributed under the License is distributed on an "AS IS" BASIS,\r
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ *    See the License for the specific language governing permissions and\r
+ *    limitations under the License.\r
+ */\r
+\r
+#include "common/app_db.h"\r
+\r
+#include <string>\r
+#include <list>\r
+\r
+class sqlite3;\r
+\r
+namespace wrt {\r
+class SqliteDB : public AppDB {\r
+ public:\r
+  explicit SqliteDB(const std::string& app_data_path = std::string());\r
+  ~SqliteDB();\r
+  virtual bool HasKey(const std::string& section,\r
+                      const std::string& key) const;\r
+  virtual std::string Get(const std::string& section,\r
+                          const std::string& key) const;\r
+  virtual void Set(const std::string& section,\r
+                   const std::string& key,\r
+                   const std::string& value);\r
+  virtual void GetKeys(const std::string& section,\r
+                       std::list<std::string>* keys) const;\r
+  virtual void Remove(const std::string& section,\r
+                      const std::string& key);\r
+\r
+ private:\r
+  void Initialize();\r
+  std::string app_data_path_;\r
+  sqlite3* sqldb_;\r
+};\r
+\r
+}  //  namespace wrt\r
index d4ad980..aca59d0 100755 (executable)
@@ -33,6 +33,7 @@ SET(UTC_COMMON_LIBS
 # Source Files
 SET(UTC_COMMON_SRCS
   ${UTC_SRCDIR}/common/utc_common_url.cc
+  ${UTC_SRCDIR}/common/utc_appdb_sqlite.cc
 )
 
 # Compiler Flags
diff --git a/tests/utc/common/utc_appdb_sqlite.cc b/tests/utc/common/utc_appdb_sqlite.cc
new file mode 100755 (executable)
index 0000000..dad7454
--- /dev/null
@@ -0,0 +1,102 @@
+/*\r
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved\r
+ *\r
+ *    Licensed under the Apache License, Version 2.0 (the "License");\r
+ *    you may not use this file except in compliance with the License.\r
+ *    You may obtain a copy of the License at\r
+ *\r
+ *        http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ *    Unless required by applicable law or agreed to in writing, software\r
+ *    distributed under the License is distributed on an "AS IS" BASIS,\r
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ *    See the License for the specific language governing permissions and\r
+ *    limitations under the License.\r
+ */\r
+\r
+#include <limits.h>\r
+\r
+#include <string>\r
+#include <iostream>\r
+\r
+#include "common/app_db_sqlite.h"\r
+#include "gtest/gtest.h"\r
+\r
+namespace wrt {\r
+\r
+namespace {\r
+  const char* kLongValue =\r
+      "01234567891123456789212345678931234567894123456789512345678961234567897"\r
+      "01234567891123456789212345678931234567894123456789512345678961234567897"\r
+      "01234567891123456789212345678931234567894123456789512345678961234567897"\r
+      "01234567891123456789212345678931234567894123456789512345678961234567897"\r
+      "01234567891123456789212345678931234567894123456789512345678961234567897"\r
+      "01234567891123456789212345678931234567894123456789512345678961234567897"\r
+      "01234567891123456789212345678931234567894123456789512345678961234567897"\r
+      "01234567891123456789212345678931234567894123456789512345678961234567897"\r
+      "01234567891123456789212345678931234567894123456789512345678961234567897"\r
+      "01234567891123456789212345678931234567894123456789512345678961234567897"\r
+      "01234567891123456789212345678931234567894123456789512345678961234567897"\r
+      "01234567891123456789212345678931234567894123456789512345678961234567897"\r
+      "01234567891123456789212345678931234567894123456789512345678961234567897"\r
+      "01234567891123456789212345678931234567894123456789512345678961234567897"\r
+      "01234567891123456789212345678931234567894123456789512345678961234567897"\r
+      "01234567891123456789212345678931234567894123456789512345678961234567897"\r
+      "01234567891123456789212345678931234567894123456789512345678961234567897"\r
+      "01234567891123456789212345678931234567894123456789512345678961234567897"\r
+      "01234567891123456789212345678931234567894123456789512345678961234567897"\r
+      "01234567891123456789212345678931234567894123456789512345678961234567897"\r
+      "01234567891123456789212345678931234567894123456789512345678961234567897"\r
+      "01234567891123456789212345678931234567894123456789512345678961234567897"\r
+      "01234567891123456789212345678931234567894123456789512345678961234567897"\r
+      "01234567891123456789212345678931234567894123456789512345678961234567897"\r
+      "01234567891123456789212345678931234567894123456789512345678961234567897";\r
+  const char* kLongKey =\r
+      "01234567891123456789212345678931234567894123456789512345678961234567897"\r
+      "01234567891123456789212345678931234567894123456789512345678961234567897"\r
+      "01234567891123456789212345678931234567894123456789512345678961234567897"\r
+      "01234567891123456789212345678931234567894123456789512345678961234567897"\r
+      "01234567891123456789212345678931234567894123456789512345678961234567897"\r
+      "01234567891123456789212345678931234567894123456789512345678961234567897"\r
+      "01234567891123456789212345678931234567894123456789512345678961234567897"\r
+      "01234567891123456789212345678931234567894123456789512345678961234567897"\r
+      "01234567891123456789212345678931234567894123456789512345678961234567897"\r
+      "01234567891123456789212345678931234567894123456789512345678961234567897"\r
+      "01234567891123456789212345678931234567894123456789512345678961234567897"\r
+      "01234567891123456789212345678931234567894123456789512345678961234567897"\r
+      "01234567891123456789212345678931234567894123456789512345678961234567897"\r
+      "01234567891123456789212345678931234567894123456789512345678961234567897"\r
+      "01234567891123456789212345678931234567894123456789512345678961234567897"\r
+      "01234567891123456789212345678931234567894123456789512345678961234567897"\r
+      "01234567891123456789212345678931234567894123456789512345678961234567897"\r
+      "01234567891123456789212345678931234567894123456789512345678961234567897"\r
+      "01234567891123456789212345678931234567894123456789512345678961234567897"\r
+      "01234567891123456789212345678931234567894123456789512345678961234567897"\r
+      "01234567891123456789212345678931234567894123456789512345678961234567897"\r
+      "01234567891123456789212345678931234567894123456789512345678961234567897"\r
+      "01234567891123456789212345678931234567894123456789512345678961234567897";\r
+}  // namespace\r
+\r
+// Tests AppDB class\r
+\r
+TEST(AppDBSqliteTest, Positive) {\r
+  SqliteDB db("/tmp/");\r
+  db.Set("test", "key1", "value1");\r
+  EXPECT_EQ(true, db.HasKey("test", "key1"));\r
+  db.Remove("test", "key1");\r
+  EXPECT_EQ(false, db.HasKey("test", "key1"));\r
+\r
+  db.Set("test", "key1", "value1");\r
+  EXPECT_EQ(std::string("value1"), db.Get("test", "key1"));\r
+\r
+  db.Set("test", "key1", "value1-1");\r
+  EXPECT_EQ(std::string("value1-1"), db.Get("test", "key1"));\r
+\r
+  db.Set("test", "longvalue", kLongValue);\r
+  EXPECT_EQ(std::string(kLongValue), db.Get("test", "longvalue"));\r
+\r
+  db.Set("test", kLongKey, "longkey");\r
+  EXPECT_EQ("longkey", db.Get("test", kLongKey));\r
+}\r
+\r
+}  // namespace wrt\r