#define CONTEXT_DB_PATH tzplatform_mkpath(TZ_USER_DB, ".context-service.db")
static bool initialized = false;
-static GThread *mainthread = NULL;
-static GMutex sync_insert_mutex;
-static GMutex sync_execute_mutex;
-static GCond sync_insert_cond;
-static GCond sync_execute_cond;
-static int64_t sync_insert_row_id = -1;
-static unsigned int sync_insert_qid = 0;
-static int sync_execute_error;
-static std::vector<ctx::json> sync_execute_result;
-static unsigned int sync_execute_qid = 0;
+static GMutex exec_mutex;
ctx::db_manager_impl::db_manager_impl()
: db_handle(NULL)
{
IF_FAIL_RETURN_TAG(!initialized, true, _W, "Re-initialization");
IF_FAIL_RETURN(open(), false);
- mainthread = g_thread_self();
IF_FAIL_RETURN(start(), false);
initialized = true;
return true;
db_handle = NULL;
}
-bool ctx::db_manager_impl::is_main_thread()
-{
- return mainthread == g_thread_self();
-}
-
void ctx::db_manager_impl::on_thread_event_popped(int type, void* data)
{
IF_FAIL_VOID(data);
query_info_s *info = static_cast<query_info_s*>(data);
switch (type) {
- case QTYPE_CREATE_TABLE:
- case QTYPE_INSERT:
- case QTYPE_EXECUTE:
- _execute(type, info->id, info->query.c_str(), info->listener);
- break;
- default:
- _W("Unknown type: %d", type);
- break;
+ case QTYPE_CREATE_TABLE:
+ case QTYPE_INSERT:
+ case QTYPE_EXECUTE:
+ _execute(type, info->id, info->query.c_str(), info->listener);
+ break;
+ default:
+ _W("Unknown type: %d", type);
+ break;
}
delete_thread_event(type, data);
delete info;
}
+std::string ctx::db_manager_impl::compose_create_query(const char* table_name, const char* columns, const char* option)
+{
+ std::string query;
+ query = "CREATE TABLE IF NOT EXISTS ";
+ query = query + table_name + " (row_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT," + columns + ")";
+ if (option) {
+ query = query + " " + option;
+ }
+ query += ";";
+ return query;
+}
+
bool ctx::db_manager_impl::create_table(unsigned int query_id, const char* table_name, const char* columns, const char* option, db_listener_iface* listener)
{
IF_FAIL_RETURN_TAG(initialized, false, _E, "Not initialized");
query_info_s *info = new(std::nothrow) query_info_s;
IF_FAIL_RETURN_TAG(info, false, _E, "Memory allocation failed");
- info->query = "CREATE TABLE IF NOT EXISTS ";
- info->query = info->query + table_name + " (row_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT," + columns + ")";
- if (option) {
- info->query = info->query + " " + option;
- }
- info->query += ";";
-
+ info->query = compose_create_query(table_name, columns, option);
info->id = query_id;
info->listener = listener;
return true;
}
-bool ctx::db_manager_impl::insert(unsigned int query_id, const char* table_name, json& record, db_listener_iface* listener)
+std::string ctx::db_manager_impl::compose_insert_query(const char* table_name, json& record)
{
- IF_FAIL_RETURN_TAG(initialized, false, _E, "Not initialized");
-
std::list<std::string> keys;
- IF_FAIL_RETURN_TAG(record.get_keys(&keys), false, _E, "Invalid record");
+ IF_FAIL_RETURN_TAG(record.get_keys(&keys), "", _E, "Invalid record");
std::ostringstream colstream;
std::ostringstream valstream;
colstream << *it << ",";
char* buf = sqlite3_mprintf("%Q", s.c_str());
- IF_FAIL_RETURN_TAG(buf, false, _E, "Memory allocation failed");
+ IF_FAIL_RETURN_TAG(buf, "", _E, "Memory allocation failed");
valstream << buf << ",";
sqlite3_free(buf);
} else if (record.get(NULL, (*it).c_str(), &i)) {
std::string cols = colstream.str();
std::string vals = valstream.str();
- IF_FAIL_RETURN_TAG(!cols.empty(), false, _E, "Invalid record");
+ IF_FAIL_RETURN_TAG(!cols.empty(), "", _E, "Invalid record");
cols.erase(cols.size() - 1);
vals.erase(vals.size() - 1);
+ std::string query = "INSERT INTO ";
+ query = query + table_name + " (" + cols + ") VALUES (" + vals + ");";
+ query = query + "SELECT seq FROM sqlite_sequence WHERE name='" + table_name + "';";
+
+ return query;
+}
+
+bool ctx::db_manager_impl::insert(unsigned int query_id, const char* table_name, json& record, db_listener_iface* listener)
+{
+ IF_FAIL_RETURN_TAG(initialized, false, _E, "Not initialized");
+
+ std::string query = compose_insert_query(table_name, record);
+ IF_FAIL_RETURN(!query.empty(), false);
+
query_info_s *info = new(std::nothrow) query_info_s;
IF_FAIL_RETURN_TAG(info, false, _E, "Memory allocation failed");
+ info->query = query;
info->id = query_id;
info->listener = listener;
- info->query = "INSERT INTO ";
- info->query = info->query + table_name + " (" + cols + ") VALUES (" + vals + ");";
- info->query = info->query + "SELECT seq FROM sqlite_sequence WHERE name='" + table_name + "';";
-
if (!push_thread_event(QTYPE_INSERT, info)) {
_E("Pushing thread event failed");
delete info;
bool ctx::db_manager_impl::execute(unsigned int query_id, const char* query, db_listener_iface* listener)
{
IF_FAIL_RETURN_TAG(initialized, false, _E, "Not initialized");
+ IF_FAIL_RETURN_TAG(query, false, _E, "Null query");
query_info_s *info = new(std::nothrow) query_info_s;
IF_FAIL_RETURN_TAG(info, false, _E, "Memory allocation failed");
void ctx::db_manager_impl::_execute(int query_type, unsigned int query_id, const char* query, db_listener_iface* listener)
{
- _SD("SQL(%d): %s", query_id, query);
IF_FAIL_VOID(query);
IF_FAIL_VOID_TAG(db_handle, _E, "DB not opened");
+ _SD("SQL(%d): %s", query_id, query);
std::vector<json> *query_result = new(std::nothrow) std::vector<json>;
IF_FAIL_VOID_TAG(query_result, _E, "Memory allocation failed");
char *err = NULL;
+ int ret;
+
+ {
+ scope_mutex sm(&exec_mutex);
+ ret = sqlite3_exec(db_handle, query, execution_result_cb, query_result, &err);
+ }
- int ret = sqlite3_exec(db_handle, query, execution_result_cb, query_result, &err);
if (ret != SQLITE_OK) {
_E("DB Error: %s", err);
sqlite3_free(err);
if (qr->listener) {
switch (qr->type) {
- case QTYPE_CREATE_TABLE:
- qr->listener->on_creation_result_received(qr->id, qr->error);
- break;
- case QTYPE_INSERT:
- {
- int64_t row_id = -1;
- if (qr->error == ERR_NONE && qr->result && !qr->result->empty()) {
- qr->result->at(0).get(NULL, "seq", &row_id);
- _D("RowId: %d", row_id);
- }
- qr->listener->on_insertion_result_received(qr->id, qr->error, row_id);
+ case QTYPE_CREATE_TABLE:
+ qr->listener->on_creation_result_received(qr->id, qr->error);
+ break;
+ case QTYPE_INSERT:
+ {
+ int64_t row_id = -1;
+ if (qr->error == ERR_NONE && qr->result && !qr->result->empty()) {
+ qr->result->at(0).get(NULL, "seq", &row_id);
+ _D("RowId: %d", row_id);
}
- break;
- case QTYPE_EXECUTE:
- qr->listener->on_query_result_received(qr->id, qr->error, *(qr->result));
- break;
- default:
- _W("Unknown query type: %d", qr->type);
+ qr->listener->on_insertion_result_received(qr->id, qr->error, row_id);
+ }
+ break;
+ case QTYPE_EXECUTE:
+ qr->listener->on_query_result_received(qr->id, qr->error, *(qr->result));
+ break;
+ default:
+ _W("Unknown query type: %d", qr->type);
}
}
return FALSE;
}
-static unsigned int generate_qid()
+bool ctx::db_manager_impl::create_table_sync(const char* table_name, const char* columns, const char* option)
{
- static GMutex mutex;
- static unsigned int qid = 0;
+ IF_FAIL_RETURN_TAG(db_handle, false, _E, "DB not opened");
- ctx::scope_mutex sm(&mutex);
+ std::string query = compose_create_query(table_name, columns, option);
+ IF_FAIL_RETURN(!query.empty(), false);
+ _SD("SQL: %s", query.c_str());
- ++qid;
+ char *err = NULL;
+ int ret;
+ {
+ scope_mutex sm(&exec_mutex);
+ ret = sqlite3_exec(db_handle, query.c_str(), NULL, NULL, &err);
+ }
- if (qid == 0) { // Overflow handling
- qid = 1;
+ if (ret != SQLITE_OK) {
+ _E("DB Error: %s", err);
+ sqlite3_free(err);
+ return false;
}
- return qid;
+ return true;
}
bool ctx::db_manager_impl::insert_sync(const char* table_name, json& record, int64_t* row_id)
{
- IF_FAIL_RETURN_TAG(initialized, false, _E, "Not initialized");
- IF_FAIL_RETURN_TAG(!db_manager_impl::is_main_thread(), false, _E, "Cannot use this in the main thread");
+ IF_FAIL_RETURN_TAG(db_handle, false, _E, "DB not opened");
IF_FAIL_RETURN_TAG(table_name && row_id, false, _E, "Invalid parameter");
- ctx::scope_mutex sm(&sync_insert_mutex);
+ std::string query = compose_insert_query(table_name, record);
+ IF_FAIL_RETURN(!query.empty(), false);
+ _SD("SQL: %s", query.c_str());
- unsigned int qid = generate_qid();
- insert(qid, table_name, record, this);
-
- while (sync_insert_qid != qid) {
- g_cond_wait(&sync_insert_cond, &sync_insert_mutex);
+ std::vector<json> query_result;
+ char *err = NULL;
+ int ret;
+ {
+ scope_mutex sm(&exec_mutex);
+ ret = sqlite3_exec(db_handle, query.c_str(), execution_result_cb, &query_result, &err);
}
- *row_id = sync_insert_row_id;
+ if (ret != SQLITE_OK) {
+ _E("DB Error: %s", err);
+ sqlite3_free(err);
+ return false;
+ }
- IF_FAIL_RETURN_TAG(*row_id > 0, false, _E, "Insertion failed");
- return true;
-}
+ IF_FAIL_RETURN_TAG(!query_result.empty(), false, _E, "No row id");
-void ctx::db_manager_impl::on_insertion_result_received(unsigned int query_id, int error, int64_t row_id)
-{
- ctx::scope_mutex sm(&sync_insert_mutex);
+ *row_id = -1;
+ query_result.at(0).get(NULL, "seq", row_id);
+ _D("RowId: %d", *row_id);
- sync_insert_row_id = row_id;
- sync_insert_qid = query_id;
-
- g_cond_signal(&sync_insert_cond);
+ return true;
}
bool ctx::db_manager_impl::execute_sync(const char* query, std::vector<json>* records)
{
- IF_FAIL_RETURN_TAG(initialized, false, _E, "Not initialized");
- IF_FAIL_RETURN_TAG(!db_manager_impl::is_main_thread(), false, _E, "Cannot use this in the main thread");
+ IF_FAIL_RETURN_TAG(db_handle, false, _E, "DB not opened");
IF_FAIL_RETURN_TAG(query && records, false, _E, "Invalid parameter");
- ctx::scope_mutex sm(&sync_execute_mutex);
+ _SD("SQL: %s", query);
- unsigned int qid = generate_qid();
- execute(qid, query, this);
-
- while (sync_execute_qid != qid) {
- g_cond_wait(&sync_execute_cond, &sync_execute_mutex);
+ char *err = NULL;
+ int ret;
+ {
+ scope_mutex sm(&exec_mutex);
+ ret = sqlite3_exec(db_handle, query, execution_result_cb, records, &err);
}
- IF_FAIL_RETURN_TAG(sync_execute_error == ERR_NONE, false, _E, "Query execution failed");
-
- *records = sync_execute_result;
- sync_execute_result.clear();
+ if (ret != SQLITE_OK) {
+ _E("DB Error: %s", err);
+ sqlite3_free(err);
+ return false;
+ }
return true;
}
-
-void ctx::db_manager_impl::on_query_result_received(unsigned int query_id, int error, std::vector<json>& records)
-{
- ctx::scope_mutex sm(&sync_execute_mutex);
-
- sync_execute_error = error;
- sync_execute_result = records;
- sync_execute_qid = query_id;
-
- g_cond_signal(&sync_execute_cond);
-}
-
-void ctx::db_manager_impl::on_creation_result_received(unsigned int query_id, int error)
-{
- _D("Table Created: QID: %d, Error: %#x", query_id, error);
-}
namespace ctx {
- class db_manager_impl : public event_driven_thread, public db_listener_iface, public db_manager_iface {
- private:
- enum query_type_e {
- QTYPE_CREATE_TABLE = 1,
- QTYPE_INSERT,
- QTYPE_EXECUTE,
- };
-
- struct query_info_s {
- unsigned int id;
- db_listener_iface* listener;
- std::string query;
- };
-
- struct query_result_s {
- int type;
- unsigned int id;
- int error;
- db_listener_iface* listener;
- std::vector<json>* result;
- };
-
- sqlite3 *db_handle;
-
- static bool is_main_thread();
-
- void on_thread_event_popped(int type, void* data);
- void delete_thread_event(int type, void* data);
-
- bool open();
- void close();
-
- void _execute(int query_type, unsigned int query_id, const char* query, db_listener_iface* listener);
- void send_result(int query_type, unsigned int query_id, db_listener_iface* listener, int error, std::vector<json>* result);
-
- static int execution_result_cb(void *user_data, int dim, char **value, char **column);
- static gboolean _send_result(gpointer data);
-
- void on_creation_result_received(unsigned int query_id, int error);
- void on_insertion_result_received(unsigned int query_id, int error, int64_t row_id);
- void on_query_result_received(unsigned int query_id, int error, std::vector<json>& records);
-
- public:
- db_manager_impl();
- ~db_manager_impl();
-
- bool init();
- void release();
-
- bool create_table(unsigned int query_id, const char* table_name, const char* columns, const char* option = NULL, db_listener_iface* listener = NULL);
- bool insert(unsigned int query_id, const char* table_name, json& record, db_listener_iface* listener = NULL);
- bool execute(unsigned int query_id, const char* query, db_listener_iface* listener);
- bool insert_sync(const char* table_name, json& record, int64_t* row_id);
- bool execute_sync(const char* query, std::vector<json>* records);
+ class db_manager_impl : public event_driven_thread, public db_manager_iface {
+ private:
+ enum query_type_e {
+ QTYPE_CREATE_TABLE = 1,
+ QTYPE_INSERT,
+ QTYPE_EXECUTE,
+ };
+
+ struct query_info_s {
+ unsigned int id;
+ db_listener_iface* listener;
+ std::string query;
+ };
+
+ struct query_result_s {
+ int type;
+ unsigned int id;
+ int error;
+ db_listener_iface* listener;
+ std::vector<json>* result;
+ };
+
+ sqlite3 *db_handle;
+
+ void on_thread_event_popped(int type, void* data);
+ void delete_thread_event(int type, void* data);
+
+ bool open();
+ void close();
+
+ std::string compose_create_query(const char* table_name, const char* columns, const char* option);
+ std::string compose_insert_query(const char* table_name, json& record);
+
+ void _execute(int query_type, unsigned int query_id, const char* query, db_listener_iface* listener);
+ void send_result(int query_type, unsigned int query_id, db_listener_iface* listener, int error, std::vector<json>* result);
+
+ static int execution_result_cb(void *user_data, int dim, char **value, char **column);
+ static gboolean _send_result(gpointer data);
+
+ public:
+ db_manager_impl();
+ ~db_manager_impl();
+
+ bool init();
+ void release();
+
+ bool create_table(unsigned int query_id, const char* table_name, const char* columns, const char* option = NULL, db_listener_iface* listener = NULL);
+ bool insert(unsigned int query_id, const char* table_name, json& record, db_listener_iface* listener = NULL);
+ bool execute(unsigned int query_id, const char* query, db_listener_iface* listener);
+
+ bool create_table_sync(const char* table_name, const char* columns, const char* option = NULL);
+ bool insert_sync(const char* table_name, json& record, int64_t* row_id);
+ bool execute_sync(const char* query, std::vector<json>* records);
}; /* class db_manager */
}