* 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;
}