Program Listing for File DatabaseHelper.cpp
↰ Return to documentation for file (lib/DatabaseHelper.cpp
)
#include "DatabaseHelper.hpp"
#include <iostream>
#include <nlohmann/json.hpp>
#include <thread>
using namespace std;
using json = nlohmann::json;
/*
Database class constructor to open sqlite3 connection
*/
Database::Database() {
int rc = sqlite3_open(getenv("DELPHI_DB"), &db);
if (rc) {
// Show an error message
cout << "DB Error: " << sqlite3_errmsg(db) << endl;
// Close the connection
sqlite3_close(db);
// Return an error
throw "Could not open db\n";
}
}
Database::~Database() {
sqlite3_close(db);
db = nullptr;
}
// Create a callback function
int callback(void* NotUsed, int argc, char** argv, char** azColName) {
// Return successful
return 0;
}
/*
Query to select/read one column and return a vector of string filled with
the column value of any table Query format: SELECT <column_name> from
<table_name>; SELECT <column_name> from <table_name> WHERE
<where_column_name> = <where_value> ;
*/
vector<string> Database::read_column_text(string query) {
vector<string> matches;
sqlite3_stmt* stmt = nullptr;
int rc = sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, NULL);
while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
const unsigned char* col_0_text = sqlite3_column_text(stmt, 0);
if(col_0_text != nullptr) {
string row_str = string(reinterpret_cast<const char*>(col_0_text));
matches.push_back(row_str);
}
}
sqlite3_finalize(stmt);
stmt = nullptr;
return matches;
}
/*
Select/read one column and all rows of any table
Query format:
SELECT <column_name> from <table_name>;
*/
vector<string> Database::read_column_text_query(string table_name,
string column_name) {
string query = "SELECT " + column_name + " from '" + table_name + "' ;";
vector<string> matches = this->read_column_text(query);
return matches;
}
/*
Select/read one column and all rows of any table with where conditioned
column and its value passed as parameters Query format: SELECT <column_name>
from <table_name> WHERE <where_column_name> = <where_value> ;
*/
vector<string> Database::read_column_text_query_where(string table_name,
string column_name,
string where_column_name,
string where_value) {
string query = "SELECT " + column_name + " from '" + table_name +
"' WHERE " + where_column_name + " = '" + where_value +
"' ;";
vector<string> matches = this->read_column_text(query);
return matches;
}
/*
Select the primary key and the model from the delphimodel table
*/
json Database::select_delphimodel_row(string modelId) {
json matches;
sqlite3_stmt* stmt = nullptr;
string query =
"SELECT * from delphimodel WHERE id='" + modelId + "' LIMIT 1;";
int rc = sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, NULL);
while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
const unsigned char* col_0_text = sqlite3_column_text(stmt, 0);
if(col_0_text != nullptr) {
matches["id"] = string(reinterpret_cast<const char*>(col_0_text));
}
const unsigned char* col_1_text = sqlite3_column_text(stmt, 1);
if(col_1_text != nullptr) {
matches["model"] = string(reinterpret_cast<const char*>(col_1_text));
}
}
sqlite3_finalize(stmt);
stmt = nullptr;
return matches;
}
/*
Select the row in the table that matches the modelId
*/
json Database::select_row(string table, string modelId, string output_field) {
json matches;
sqlite3_stmt* stmt = nullptr;
string query =
"SELECT * from " + table + " WHERE id='" + modelId + "' LIMIT 1;";
int rc = sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, NULL);
while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
const unsigned char* col_0_text = sqlite3_column_text(stmt, 0);
if(col_0_text != nullptr) {
matches["id"] = string(reinterpret_cast<const char*>(col_0_text));
}
const unsigned char* col_1_text = sqlite3_column_text(stmt, 1);
if(col_1_text != nullptr) {
matches[output_field] = string(reinterpret_cast<const char*>(col_1_text));
}
}
sqlite3_finalize(stmt);
stmt = nullptr;
return matches;
}
/*
Select/read all column and 1 rows of causemosasyncexperimentresult table
*/
json Database::select_causemosasyncexperimentresult_row(string modelId) {
json matches;
sqlite3_stmt* stmt = nullptr;
string query = "SELECT * from causemosasyncexperimentresult WHERE id='" +
modelId + "' LIMIT 1;";
int rc = sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, NULL);
while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
const unsigned char* col_0_text = sqlite3_column_text(stmt, 0);
if(col_0_text != nullptr) {
matches["id"] = string(reinterpret_cast<const char*>(col_0_text));
}
const unsigned char* col_1_text = sqlite3_column_text(stmt, 1);
if(col_1_text != nullptr) {
matches["status"] = string(reinterpret_cast<const char*>(col_1_text));
}
const unsigned char* col_2_text = sqlite3_column_text(stmt, 2);
if(col_2_text != nullptr) {
matches["experimentType"] = string(reinterpret_cast<const char*>(col_2_text));
}
const unsigned char* col_3_text = sqlite3_column_text(stmt, 3);
if(col_3_text != nullptr) {
matches["results"] = string(reinterpret_cast<const char*>(col_3_text));
}
}
sqlite3_finalize(stmt);
stmt = nullptr;
return matches;
}
/*
Execute insert query string on any table
*/
bool Database::insert(string insert_query) {
return exec_query(insert_query);
}
/*
Execute insert/replace query string on delphimodel table for 1 row
*/
bool Database::insert_into_delphimodel(string id, string model) {
string query =
"INSERT OR REPLACE INTO delphimodel ('id', 'model') VALUES ('" + id +
"', '" + model + "');";
return insert(query);
}
/*
Execute insert/replace query string on causemosasyncexperimentresult table
for 1 row
*/
bool Database::insert_into_causemosasyncexperimentresult(string id,
string status,
string experimentType,
string results) {
string query = "INSERT OR REPLACE INTO causemosasyncexperimentresult "
"('id', 'status', 'experimentType', 'results') VALUES ('" +
id + "', '" + status + "', '" + experimentType + "', '" +
results + "'); ";
return insert(query);
}
/* Execute the query on the database, retry if busy, report errors */
bool Database::exec_query(string query) {
int max_attempts = 100; // usually only takes a few attempts.
string fn = "DatabaseHelper::exec ";
for(int i = 0; i < max_attempts; i ++) {
int rc = sqlite3_exec(db, query.c_str(), callback, 0, NULL);
switch (rc) {
case SQLITE_OK: // success
if(i > 0) {
cout << fn << "succeeded after " << i+1 << " attempts " << endl;
}
return true;
case SQLITE_BUSY: // blocked by busy db, wait a moment and retry
this_thread::sleep_for(std::chrono::seconds(1));
break;
default: // failure
cout << fn << "failed with error code: " << rc << endl;
return false;
}
}
// maxed out the number of attempts, something is wrong.
cout << fn << "could not execute after " << max_attempts << " attempts";
return false;
}