From e5464d0027f05b72a22132e092ada1f71a96d65a Mon Sep 17 00:00:00 2001 From: Mu-Woong Lee Date: Wed, 8 Feb 2017 17:50:33 +0900 Subject: [PATCH] Add initial implementation of the class Database Change-Id: I79e9c79d43aa545e3e5ffe42ceb851e569e08650 Signed-off-by: Mu-Woong Lee --- include/Credential.h | 2 + include/Database.h | 27 +++++- src/server/Credential.cpp | 5 + src/server/Database.cpp | 231 +++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 262 insertions(+), 3 deletions(-) diff --git a/include/Credential.h b/include/Credential.h index 359a9ba..006d9bb 100644 --- a/include/Credential.h +++ b/include/Credential.h @@ -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 */ diff --git a/include/Database.h b/include/Database.h index 4e66ba1..b99dc2e 100644 --- a/include/Database.h +++ b/include/Database.h @@ -18,16 +18,39 @@ #define __CONTEXT_DATABASE_H__ #include +#include #include +#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* columnNames, std::vector* queryResult); + bool execute(const std::string& query, std::vector* queryResult); + + void beginTransaction(); + void endTransaction(); + + private: + sqlite3* __dbHandle; + std::string __dbPath; + bool __transactionOn; }; } diff --git a/src/server/Credential.cpp b/src/server/Credential.cpp index e9adc83..f2d201c 100644 --- a/src/server/Credential.cpp +++ b/src/server/Credential.cpp @@ -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); +} diff --git a/src/server/Database.cpp b/src/server/Database.cpp index a707e0f..222cd13 100644 --- a/src/server/Database.cpp +++ b/src/server/Database.cpp @@ -14,14 +14,243 @@ * limitations under the License. */ +#include +#include +#include +#include +#include #include +#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(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* columnNames; + std::vector* queryResult; + ExecutionCbData(const std::string* types, std::vector* names, std::vector* result) : + columnTypes(types), + columnNames(names), + queryResult(result) + { + } +}; + +static inline void __setColumnNames(int dim, char** src, std::vector* 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(userData); + + __setColumnNames(dim, column, cbData->columnNames); + + if (!cbData->queryResult) + return E_NONE; + + Tuple::Builder builder; + + for (unsigned int i = 0; i < static_cast(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* columnNames, std::vector* 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* 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; } -- 2.7.4