Add initial implementation of the class Database 56/113656/1
authorMu-Woong Lee <muwoong.lee@samsung.com>
Wed, 8 Feb 2017 08:50:33 +0000 (17:50 +0900)
committerMu-Woong Lee <muwoong.lee@samsung.com>
Wed, 8 Feb 2017 08:50:33 +0000 (17:50 +0900)
Change-Id: I79e9c79d43aa545e3e5ffe42ceb851e569e08650
Signed-off-by: Mu-Woong Lee <muwoong.lee@samsung.com>
include/Credential.h
include/Database.h
src/server/Credential.cpp
src/server/Database.cpp

index 359a9ba..006d9bb 100644 (file)
@@ -30,6 +30,8 @@ namespace ctx {
                bool valid();
                bool hasPrivilege(const char* privil);
 
+               std::string getUser() const;
+
        private:
                pid_t __pid;
                char* __clientId;       /* Tizen-Default: Smack label */
index 4e66ba1..b99dc2e 100644 (file)
 #define __CONTEXT_DATABASE_H__
 
 #include <string>
+#include <vector>
 #include <ContextTypes.h>
 
+#define COL_INT64      "x"
+#define COL_DOUBLE     "d"
+#define COL_STRING     "s"
+
+struct sqlite3;
+
 namespace ctx {
 
+       class Credential;
+       class Tuple;
+
        class EXPORT_API Database {
        public:
-               Database(std::string user, std::string name);
+               Database(const std::string& dbName, const Credential* credential);
+               Database(const std::string& dbName);
                ~Database();
 
-               bool execute(std::string query /* TODO: Outparam for query results */);
+               bool open();
+               void close();
+
+               bool execute(const std::string& query, const std::string& columnTypes, std::vector<std::string>* columnNames, std::vector<Tuple*>* queryResult);
+               bool execute(const std::string& query, std::vector<Tuple*>* queryResult);
+
+               void beginTransaction();
+               void endTransaction();
+
+       private:
+               sqlite3* __dbHandle;
+               std::string __dbPath;
+               bool __transactionOn;
        };
 
 }
index e9adc83..f2d201c 100644 (file)
@@ -128,3 +128,8 @@ bool Credential::hasPrivilege(const char* privil)
        _D("Checking '%s' for '%s'", privil, __clientId);
        return privilegeChecker.hasPrivilege(__clientId, __session, __user, privil);
 }
+
+std::string Credential::getUser() const
+{
+       return std::string(__user);
+}
index a707e0f..222cd13 100644 (file)
  * limitations under the License.
  */
 
+#include <sqlite3.h>
+#include <tzplatform_config.h>
+#include <ScopeMutex.h>
+#include <Credential.h>
+#include <Tuple.h>
 #include <Database.h>
 
+#define SYSTEM_UID_LIMIT       5000
+
 using namespace ctx;
 
-Database::Database(std::string user, std::string name)
+static GMutex __pathMutex;
+
+static std::string __getSystemPath(const std::string& dbName)
+{
+       std::string path = "." + dbName + ".db";
+
+       {
+               ScopeMutex sm(&__pathMutex);
+               path = tzplatform_mkpath(TZ_SYS_DB, path.c_str());
+       }
+
+       return path;
+}
+
+static std::string __getUserPath(const std::string& dbName, uid_t uid)
+{
+       std::string path = "." + dbName + ".db";
+
+       tzplatform_context* context = NULL;
+       tzplatform_context_create(&context);
+       IF_FAIL_RETURN_TAG(context, "", _E, "tzplatform_context_create() failed");
+
+       if (tzplatform_context_set_user(context, uid) != E_NONE) {
+               _E("tzplatform_context_set_user() failed");
+               tzplatform_context_destroy(context);
+               return "";
+       }
+
+       {
+               ScopeMutex sm(&__pathMutex);
+               path = tzplatform_context_mkpath(context, TZ_USER_DB, path.c_str());
+       }
+
+       tzplatform_context_destroy(context);
+
+       return path;
+}
+
+Database::Database(const std::string& dbName, const Credential* credential) :
+       __dbHandle(NULL),
+       __transactionOn(false)
+{
+       uid_t uid = static_cast<uid_t>(atoll(credential->getUser().c_str()));
+
+       if (uid < SYSTEM_UID_LIMIT) {
+               __dbPath = __getSystemPath(dbName);
+       } else {
+               __dbPath = __getUserPath(dbName, uid);
+       }
+
+       _I("Path: %s", __dbPath.c_str());
+}
+
+Database::Database(const std::string& dbName) :
+       __dbHandle(NULL),
+       __transactionOn(false)
 {
+       __dbPath = __getSystemPath(dbName);
+
+       _I("Path: %s", __dbPath.c_str());
 }
 
 Database::~Database()
 {
+       close();
+}
+
+bool Database::open()
+{
+       IF_FAIL_RETURN(__dbPath.size() > 0, false);
+       _D("Path: %s", __dbPath.c_str());
+
+       sqlite3 *db = NULL;
+       char *err = NULL;
+       int ret;
+
+       ret = sqlite3_open(__dbPath.c_str(), &db);
+       IF_FAIL_RETURN_TAG(ret == SQLITE_OK, false, _E, "Error: %s", sqlite3_errmsg(db));
+
+       ret = sqlite3_exec(db, "PRAGMA journal_mode = WAL", NULL, NULL, &err);
+       if (ret != SQLITE_OK) {
+               _E("Setting journal mode failed: %s", err);
+               sqlite3_free(err);
+               sqlite3_close(db);
+               return false;
+       }
+
+       __dbHandle = db;
+       return true;
+}
+
+void Database::close()
+{
+       endTransaction();
+
+       if (__dbHandle) {
+               _D("Path: %s", __dbPath.c_str());
+               sqlite3_close(__dbHandle);
+               __dbHandle = NULL;
+       }
+}
+
+struct ExecutionCbData {
+       const std::string* columnTypes;
+       std::vector<std::string>* columnNames;
+       std::vector<Tuple*>* queryResult;
+       ExecutionCbData(const std::string* types, std::vector<std::string>* names, std::vector<Tuple*>* result) :
+               columnTypes(types),
+               columnNames(names),
+               queryResult(result)
+       {
+       }
+};
+
+static inline void __setColumnNames(int dim, char** src, std::vector<std::string>* dest)
+{
+       if (!dest || !dest->empty()) return;
+
+       for (int i = 0; i < dim; ++i) {
+               dest->push_back(std::string(src[i]));
+       }
+}
+
+static inline int64_t __toInt64(const char* str)
+{
+       if (!str)
+               return 0;
+
+       return atoll(str);
+}
+
+static inline double __toDouble(const char* str)
+{
+       if (!str)
+               return 0;
+
+       return atof(str);
+}
+
+static inline std::string __toString(const char* str)
+{
+       if (!str)
+               return "";
+
+       return str;
+}
+
+static int __executionCb(void *userData, int dim, char** value, char** column)
+{
+       ExecutionCbData* cbData = static_cast<ExecutionCbData*>(userData);
+
+       __setColumnNames(dim, column, cbData->columnNames);
+
+       if (!cbData->queryResult)
+               return E_NONE;
+
+       Tuple::Builder builder;
+
+       for (unsigned int i = 0; i < static_cast<unsigned int>(dim); ++i) {
+               try {
+                       if (cbData->columnTypes->at(i) == *COL_INT64) {
+                               builder.add(__toInt64(value[i]));
+                       } else if (cbData->columnTypes->at(i) == *COL_DOUBLE) {
+                               builder.add(__toDouble(value[i]));
+                       } else {
+                               builder.add(__toString(value[i]));
+                       }
+               } catch(std::exception& e) {
+                       builder.add(__toString(value[i]));
+               }
+       }
+
+       Tuple* tuple = builder.build();
+       IF_FAIL_RETURN_TAG(tuple, E_NO_MEM, _E, "Memory allocation failed");
+
+       cbData->queryResult->push_back(tuple);
+       return E_NONE;
+}
+
+bool Database::execute(const std::string& query, const std::string& columnTypes,
+               std::vector<std::string>* columnNames, std::vector<Tuple*>* queryResult)
+{
+       IF_FAIL_RETURN_TAG(__dbHandle, false, _E, "Not opened");
+       _SD("%s", query.c_str());
+
+       ExecutionCbData* cbData = new(std::nothrow) ExecutionCbData(&columnTypes, columnNames, queryResult);
+       IF_FAIL_RETURN_TAG(cbData, false, _E, "Memory allocation failed");
+
+       char* err = NULL;
+       int ret = sqlite3_exec(__dbHandle, query.c_str(), __executionCb, cbData, &err);
+
+       delete cbData;
+
+       if (ret != SQLITE_OK) {
+               _E("Error: %s", err);
+               sqlite3_free(err);
+               return false;
+       }
+
+       return true;
+}
+
+bool Database::execute(const std::string& query, std::vector<Tuple*>* result)
+{
+       return execute(query, "", NULL, result);
+}
+
+void Database::beginTransaction()
+{
+       IF_FAIL_VOID_TAG(__dbHandle, _E, "Not opened");
+
+       static const char* beginQuery = "BEGIN EXCLUSIVE TRANSACTION";
+       _D("%s", beginQuery);
+
+       sqlite3_exec(__dbHandle, beginQuery, NULL, NULL, NULL);
+       __transactionOn = true;
+}
+
+void Database::endTransaction()
+{
+       IF_FAIL_VOID(__dbHandle);
+       IF_FAIL_VOID(__transactionOn);
+
+       static const char* endQuery = "COMMIT TRANSACTION";
+       _D("%s", endQuery);
+
+       sqlite3_exec(__dbHandle, endQuery, NULL, NULL, NULL);
+       __transactionOn = false;
 }