169 lines
5.9 KiB
C++
169 lines
5.9 KiB
C++
#include <src/log/LogUtils.h>
|
|
#include "SqliteSQL.h"
|
|
|
|
using namespace std;
|
|
using namespace sql;
|
|
using namespace sqlite;
|
|
|
|
SqliteManager::SqliteManager() : SqlManager(SqlType::TYPE_SQLITE) { }
|
|
|
|
SqliteManager::~SqliteManager() {
|
|
if(this->connected()) this->disconnect();
|
|
}
|
|
|
|
result SqliteManager::connect(const std::string &string) {
|
|
auto url = string;
|
|
if(url.find("sqlite://") == 0) url = url.substr(strlen("sqlite://"));
|
|
|
|
auto result = sqlite3_open(url.c_str(), &this->database);
|
|
if(!this->database)
|
|
return {"connect", -1, "could not open database. Code: " + to_string(result)};
|
|
return result::success;
|
|
}
|
|
|
|
bool SqliteManager::connected() {
|
|
return this->database != nullptr;
|
|
}
|
|
|
|
result SqliteManager::disconnect() {
|
|
if(!this->database)
|
|
return {"disconnect", -1, "database not open"};
|
|
this->pool->threads()->wait_for();
|
|
auto result = sqlite3_close(this->database);
|
|
if(result == 0) {
|
|
this->database = nullptr;
|
|
return result::success;
|
|
};
|
|
return {"disconnect", -1, "Failed to close database. Code: " + to_string(result)};
|
|
}
|
|
|
|
std::shared_ptr<CommandData> SqliteManager::allocateCommandData() {
|
|
return std::make_shared<SqliteCommand>();
|
|
}
|
|
|
|
std::shared_ptr<CommandData> SqliteManager::copyCommandData(std::shared_ptr<CommandData> ptr) {
|
|
auto _new = this->allocateCommandData();
|
|
_new->handle = ptr->handle;
|
|
_new->lock = ptr->lock;
|
|
_new->sql_command = ptr->sql_command;
|
|
_new->variables = ptr->variables;
|
|
|
|
auto __new = static_pointer_cast<SqliteCommand>(_new);
|
|
auto __ptr = static_pointer_cast<SqliteCommand>(ptr);
|
|
__new->stmt = __ptr->stmt;
|
|
return __new;
|
|
}
|
|
|
|
namespace sql {
|
|
namespace sqlite {
|
|
inline void bindVariable(sqlite3_stmt* stmt, int& valueIndex, const variable& val){
|
|
valueIndex = sqlite3_bind_parameter_index(stmt, val.key().c_str());
|
|
if(valueIndex == 0){ //TODO maybe throw an exception
|
|
//cerr << "Cant find variable '" + val.key() + "' -> '" + val.value() + "' in query '" + sqlite3_sql(stmt) + "'" << endl;
|
|
return;
|
|
}
|
|
|
|
|
|
int resultState = 0;
|
|
if(val.type() == VARTYPE_NULL)
|
|
resultState = sqlite3_bind_null(stmt, valueIndex);
|
|
else if(val.type() == VARTYPE_TEXT)
|
|
resultState = sqlite3_bind_text(stmt, valueIndex, val.value().c_str(), val.value().length(), SQLITE_TRANSIENT);
|
|
else if(val.type() == VARTYPE_INT || val.type() == VARTYPE_BOOLEAN)
|
|
resultState = sqlite3_bind_int(stmt, valueIndex, val.as<int32_t>());
|
|
else if(val.type() == VARTYPE_LONG)
|
|
resultState = sqlite3_bind_int64(stmt, valueIndex, val.as<int64_t>());
|
|
else if(val.type() == VARTYPE_DOUBLE || val.type() == VARTYPE_FLOAT)
|
|
resultState = sqlite3_bind_double(stmt, valueIndex, val.as<double>());
|
|
else cerr << "Invalid value type!" << endl; //TODO throw exception
|
|
|
|
if(resultState != SQLITE_OK){
|
|
cerr << "Invalid bind. " << sqlite3_errmsg(sqlite3_db_handle(stmt)) << " Index: " << valueIndex << endl; //TODO throw exception
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
std::shared_ptr<sqlite3_stmt> SqliteManager::allocateStatement(const std::string& command) {
|
|
sqlite3_stmt* stmt;
|
|
if(sqlite3_prepare_v2(this->database, command.data(), static_cast<int>(command.length()), &stmt, nullptr) != SQLITE_OK)
|
|
return nullptr;
|
|
|
|
return std::shared_ptr<sqlite3_stmt>(stmt, [](void* _ptr) {
|
|
auto _stmt = static_cast<sqlite3_stmt*>(_ptr);
|
|
if(_stmt) sqlite3_finalize(_stmt);
|
|
});
|
|
}
|
|
|
|
result SqliteManager::queryCommand(std::shared_ptr<CommandData> _ptr, const QueryCallback &fn) {
|
|
auto ptr = static_pointer_cast<SqliteCommand>(_ptr);
|
|
std::lock_guard<threads::Mutex> lock(ptr->lock);
|
|
|
|
result res;
|
|
std::shared_ptr<sqlite3_stmt> stmt;
|
|
if(ptr->stmt){
|
|
stmt = ptr->stmt;
|
|
sqlite3_reset(stmt.get());
|
|
} else {
|
|
ptr->stmt = this->allocateStatement(ptr->sql_command);
|
|
if(!ptr->stmt)
|
|
return {_ptr->sql_command,1, sqlite3_errmsg(ptr->sqlHandle<SqliteManager>()->database)};
|
|
stmt = ptr->stmt;
|
|
}
|
|
|
|
int varIndex = 0;
|
|
for(auto& var : ptr->variables)
|
|
bindVariable(stmt.get(), varIndex, var);
|
|
|
|
int result = 0;
|
|
int columnCount = sqlite3_column_count(stmt.get());
|
|
std::string columnNames[columnCount];
|
|
std::string columnValues[columnCount];
|
|
|
|
for(int column = 0; column < columnCount; column++) {
|
|
auto tmp = sqlite3_column_name(stmt.get(), column);
|
|
columnNames[column] = tmp ? tmp : "";
|
|
}
|
|
|
|
bool userQuit = false;
|
|
while((result = sqlite3_step(stmt.get())) == SQLITE_ROW){
|
|
for(int column = 0; column < columnCount; column++) {
|
|
const auto * tmp = reinterpret_cast<const char *>(sqlite3_column_text(stmt.get(), column));
|
|
columnValues[column] = tmp ? tmp : "";
|
|
}
|
|
if(fn(columnCount, columnValues, columnNames) != 0) {
|
|
userQuit = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(result != SQLITE_DONE && !userQuit) return {_ptr->sql_command,result, sqlite3_errstr(result)};
|
|
return {_ptr->sql_command,0, "success"};
|
|
}
|
|
|
|
result SqliteManager::executeCommand(std::shared_ptr<CommandData> _ptr) {
|
|
auto ptr = static_pointer_cast<SqliteCommand>(_ptr);
|
|
std::lock_guard<threads::Mutex> lock(ptr->lock);
|
|
|
|
result res;
|
|
sqlite3_stmt* stmt;
|
|
if(ptr->stmt){
|
|
stmt = ptr->stmt.get();
|
|
sqlite3_reset(stmt);
|
|
} else {
|
|
ptr->stmt = this->allocateStatement(ptr->sql_command);
|
|
if(!ptr->stmt)
|
|
return {_ptr->sql_command,1, sqlite3_errmsg(ptr->sqlHandle<SqliteManager>()->database)};
|
|
stmt = ptr->stmt.get();
|
|
}
|
|
|
|
int varIndex = 0;
|
|
for(const auto& var : ptr->variables)
|
|
bindVariable(stmt, varIndex, var);
|
|
|
|
int result = sqlite3_step(stmt);
|
|
if(result == SQLITE_DONE)
|
|
return {_ptr->sql_command,0, "success"};
|
|
if(result == SQLITE_ROW) return {_ptr->sql_command,-1, "query has a result"};
|
|
return {_ptr->sql_command, 1, sqlite3_errstr(result)};
|
|
} |