Program Listing for File SQLiteHandler.cpp¶
↰ Return to documentation for file (necsim/SQLiteHandler.cpp
)
// This file is part of necsim project which is released under MIT license.
// See file **LICENSE.txt** or visit https://opensource.org/licenses/MIT) for full license details.
#include "SQLiteHandler.h"
namespace necsim
{
SQLStatement::SQLStatement() : last_command(), stmt(nullptr)
{
}
int SQLStatement::step()
{
int rc = sqlite3_step(stmt);
time_t start_check, end_check;
time(&start_check);
time(&end_check);
// Note that a 10 second threshold is used to wait for output before raising an error.
while(rc != SQLITE_DONE && (end_check - start_check) < 10 && rc != SQLITE_OK && rc != SQLITE_ROW
&& (rc == SQLITE_BUSY || rc == SQLITE_LOCKED))
{
rc = sqlite3_step(stmt);
sleep(1);
time(&end_check);
}
return rc;
}
void SQLStatement::clearAndReset()
{
sqlite3_clear_bindings(stmt);
sqlite3_reset(stmt);
}
SQLiteHandler::SQLiteHandler() : database(nullptr), file_name(), stmt(nullptr)
{
}
SQLiteHandler::~SQLiteHandler()
{
close();
}
void SQLiteHandler::open(const std::string &file_name)
{
openSQLiteDatabase(file_name, database);
this->file_name = file_name;
}
void SQLiteHandler::close()
{
sqlite3_close_v2(database);
database = nullptr;
}
std::string SQLiteHandler::getErrorMsg(int rc)
{
std::stringstream ss;
ss << "Error code: " << rc << ": " << getErrorMsg();
return ss.str();
}
std::string SQLiteHandler::getErrorMsg()
{
return sqlite3_errmsg(database);
}
void SQLiteHandler::backupFrom(SQLiteHandler &sqlite_handler)
{
sqlite3_backup* backupdb = sqlite3_backup_init(database, "main", sqlite_handler.database, "main");
int rc = sqlite3_backup_step(backupdb, -1);
int counter = 0;
while(counter < 10 && (rc == SQLITE_BUSY || rc == SQLITE_LOCKED))
{
counter++;
rc = sqlite3_backup_step(backupdb, -1);
sleep(1);
}
if(rc != SQLITE_OK && rc != SQLITE_DONE)
{
std::stringstream ss;
ss << "Database backup cannot be completed to " << file_name << " from " << sqlite_handler.file_name;
ss << ". Check write access on output folder." << endl << getErrorMsg(rc);
throw FatalException(ss.str());
}
rc = sqlite3_backup_finish(backupdb);
// os << "rc: " << rc << endl;
if(rc != SQLITE_DONE && rc != SQLITE_OK)
{
std::stringstream ss;
ss << "Database backup cannot be finished to " << file_name << " from " << sqlite_handler.file_name;
ss << ". Check write access on output folder." << endl << getErrorMsg(rc);
throw FatalException(ss.str());
}
}
shared_ptr<SQLStatement> SQLiteHandler::prepare(const std::string &command)
{
createStatement();
int rc = sqlite3_prepare_v2(database, command.c_str(), static_cast<int>(strlen(command.c_str())), &stmt->stmt,
nullptr);
if(rc != SQLITE_OK && rc != SQLITE_DONE)
{
std::stringstream ss;
ss << "Could not prepare statement: " << command << endl << getErrorMsg(rc);
throw FatalException(ss.str());
}
stmt->last_command = command;
return stmt;
}
void SQLiteHandler::createStatement()
{
stmt = make_shared<SQLStatement>();
}
void SQLiteHandler::useStatement(shared_ptr<SQLStatement> stmt)
{
this->stmt = stmt;
}
void SQLiteHandler::step()
{
int rc = stmt->step();
if(rc != SQLITE_OK && rc != SQLITE_DONE && rc != SQLITE_ROW)
{
std::stringstream ss;
ss << "Could not step statement: " << stmt->last_command << endl;
ss << getErrorMsg(rc);
throw FatalException(ss.str());
}
}
void SQLiteHandler::finalise()
{
int rc = sqlite3_finalize(stmt->stmt);
if(rc != SQLITE_OK && rc != SQLITE_DONE)
{
std::stringstream ss;
ss << "Could not finalise statement: " << getErrorMsg(rc);
throw FatalException(ss.str());
}
}
void SQLiteHandler::execute(const string &command)
{
int rc = sqlite3_exec(database, command.c_str(), nullptr, nullptr, nullptr);
if(rc != SQLITE_OK && rc != SQLITE_DONE)
{
std::stringstream ss;
ss << "Could not execute statement: " << command << endl;
ss << getErrorMsg(rc);
throw FatalException(ss.str());
}
}
void SQLiteHandler::beginTransaction()
{
execute("BEGIN TRANSACTION;");
}
void SQLiteHandler::endTransaction()
{
execute("END TRANSACTION;");
}
bool SQLiteHandler::isOpen()
{
return database != nullptr;
}
bool SQLiteHandler::hasTable(const std::string &table_name)
{
string call1 = "select count(type) from sqlite_master where type='table' and name='" + table_name + "'";
prepare(call1);
step();
auto has_table = static_cast<bool>(sqlite3_column_int(stmt->stmt, 0));
finalise();
return has_table;
}
}