Adding support to get the last inserted row

This commit is contained in:
WolverinDEV 2021-02-22 18:55:35 +01:00
parent 6e99fc1ab4
commit 539d94e724
5 changed files with 140 additions and 113 deletions

View File

@ -33,26 +33,23 @@ namespace sql {
class result { class result {
public: public:
static result success; static result success;
result() : result(success) { }
result(std::string query, int code, std::string msg) : _code(code), _msg(std::move(msg)), _sql(std::move(query)) { }
result(int code, const std::string &msg) : _code(code), _msg(std::move(msg)) { }
result(const result& ref) : _code(ref._code), _msg(ref._msg), _sql(ref._sql) { }
result(result&& ref) : _code(ref._code), _msg(std::move(ref._msg)), _sql(std::move(ref._sql)) { }
virtual ~result() { };
int code() const { return _code; } result() : result{success} { }
std::string msg() const { return _msg; } result(std::string query, int code, int64_t last_insert_rowid, std::string msg)
std::string sql() const { return _sql; } : code_{code}, msg_{std::move(msg)}, sql_{std::move(query)}, last_insert_rowid_{last_insert_rowid} { }
result(const result&) = default;
result(result&&) = default;
result& operator=(const result&) = default;
result& operator=(result&&) = default;
int code() const { return this->code_; }
std::string msg() const { return this->msg_; }
std::string sql() const { return this->sql_; }
int64_t last_insert_rowid() const { return this->last_insert_rowid_; };
//Returns true on success //Returns true on success
operator bool() const { return _code == 0; } operator bool() const { return code_ == 0; }
result&operator=(const result& other) {
this->_code = other._code;
this->_msg = other._msg;
this->_sql = other._sql;
return *this;
}
std::string fmtStr() const { std::string fmtStr() const {
std::stringstream s; std::stringstream s;
@ -60,9 +57,10 @@ namespace sql {
return s.str(); return s.str();
} }
private: private:
int _code = 0; int code_{0};
std::string _msg{}; int64_t last_insert_rowid_{0};
std::string _sql{}; std::string msg_{};
std::string sql_{};
}; };
enum SqlType { enum SqlType {

View File

@ -26,8 +26,9 @@ MySQLManager::~MySQLManager() {}
#define MYSQL_PREFIX "mysql://" #define MYSQL_PREFIX "mysql://"
inline result parse_url(const string& url, std::map<std::string, std::string>& connect_map) { inline result parse_url(const string& url, std::map<std::string, std::string>& connect_map) {
string target_url; string target_url;
if(url.find(MYSQL_PREFIX) != 0) if(url.find(MYSQL_PREFIX) != 0) {
return {ERROR_MYSQL_INVLID_URL, "Missing mysql:// at begin"}; return {"", ERROR_MYSQL_INVLID_URL, -1, "Missing mysql:// at begin"};
}
auto index_parms = url.find('?'); auto index_parms = url.find('?');
if(index_parms == string::npos) { if(index_parms == string::npos) {
@ -184,7 +185,7 @@ result MySQLManager::connect(const std::string &url) {
if(!parse_mysql_data(url, error, host, port, database, properties)) { if(!parse_mysql_data(url, error, host, port, database, properties)) {
error = "URL parsing failed: " + error; error = "URL parsing failed: " + error;
return {ERROR_MYSQL_INVLID_URL, error}; return {"", ERROR_MYSQL_INVLID_URL, -1, error};
} }
size_t connections = 4; size_t connections = 4;
@ -192,17 +193,17 @@ result MySQLManager::connect(const std::string &url) {
try { try {
connections = stol(properties["connections"]); connections = stol(properties["connections"]);
} catch(std::exception& ex) { } catch(std::exception& ex) {
return {ERROR_MYSQL_INVLID_PROPERTIES, "could not parse connection count"}; return {"", ERROR_MYSQL_INVLID_PROPERTIES, -1, "could not parse connection count"};
} }
} }
string username, password; string username, password;
if(properties.count("userName") > 0) username = properties["userName"]; if(properties.count("userName") > 0) username = properties["userName"];
if(properties.count("username") > 0) username = properties["username"]; if(properties.count("username") > 0) username = properties["username"];
if(username.empty()) return {ERROR_MYSQL_INVLID_PROPERTIES, "missing username property"}; if(username.empty()) return {"", ERROR_MYSQL_INVLID_PROPERTIES, -1, "missing username property"};
if(properties.count("password") > 0) password = properties["password"]; if(properties.count("password") > 0) password = properties["password"];
if(password.empty()) return {ERROR_MYSQL_INVLID_PROPERTIES, "missing password property"}; if(password.empty()) return {"", ERROR_MYSQL_INVLID_PROPERTIES, -1, "missing password property"};
//debugMessage(LOG_GENERAL, R"([MYSQL] Starting {} connections to {}:{} with database "{}" as user "{}")", connections, host, port, database, username); //debugMessage(LOG_GENERAL, R"([MYSQL] Starting {} connections to {}:{} with database "{}" as user "{}")", connections, host, port, database, username);
@ -210,7 +211,7 @@ result MySQLManager::connect(const std::string &url) {
auto connection = make_shared<Connection>(); auto connection = make_shared<Connection>();
connection->handle = mysql_init(nullptr); connection->handle = mysql_init(nullptr);
if(!connection->handle) if(!connection->handle)
return {-1, "failed to allocate connection " + to_string(index)}; return {"", -1, -1, "failed to allocate connection " + to_string(index)};
{ {
uint32_t reconnect{true}; uint32_t reconnect{true};
@ -221,7 +222,7 @@ result MySQLManager::connect(const std::string &url) {
auto result = mysql_real_connect(connection->handle, host.c_str(), username.c_str(), password.c_str(), database.c_str(), port, nullptr, 0); //CLIENT_MULTI_RESULTS | CLIENT_MULTI_STATEMENTS auto result = mysql_real_connect(connection->handle, host.c_str(), username.c_str(), password.c_str(), database.c_str(), port, nullptr, 0); //CLIENT_MULTI_RESULTS | CLIENT_MULTI_STATEMENTS
if(!result) if(!result)
return {-1, "failed to connect to server with connection " + to_string(index) + ": " + mysql_error(connection->handle)}; return {"", -1, -1, "failed to connect to server with connection " + to_string(index) + ": " + mysql_error(connection->handle)};
connection->used = false; connection->used = false;
this->connections.push_back(connection); this->connections.push_back(connection);
@ -230,12 +231,12 @@ result MySQLManager::connect(const std::string &url) {
} }
bool MySQLManager::connected() { bool MySQLManager::connected() {
lock_guard<mutex> lock(this->connections_lock); lock_guard<mutex> lock(this->connections_mutex);
return !this->connections.empty(); return !this->connections.empty();
} }
result MySQLManager::disconnect() { result MySQLManager::disconnect() {
lock_guard<mutex> lock(this->connections_lock); lock_guard<mutex> lock(this->connections_mutex);
this->disconnecting = true; this->disconnecting = true;
this->connections.clear(); this->connections.clear();
@ -634,14 +635,14 @@ AcquiredConnection::~AcquiredConnection() {
} }
{ {
lock_guard lock(this->owner->connections_lock); lock_guard lock(this->owner->connections_mutex);
this->owner->connections_condition.notify_one(); this->owner->connections_condition.notify_one();
} }
} }
std::unique_ptr<AcquiredConnection> MySQLManager::next_connection() { std::unique_ptr<AcquiredConnection> MySQLManager::next_connection() {
unique_ptr<AcquiredConnection> result; unique_ptr<AcquiredConnection> result;
{ {
unique_lock connections_lock(this->connections_lock); unique_lock connections_lock(this->connections_mutex);
while(!result) { while(!result) {
size_t available_connections = 0; size_t available_connections = 0;
@ -676,118 +677,136 @@ std::unique_ptr<AcquiredConnection> MySQLManager::next_connection() {
} }
void MySQLManager::connection_closed(const std::shared_ptr<sql::mysql::Connection> &connection) { void MySQLManager::connection_closed(const std::shared_ptr<sql::mysql::Connection> &connection) {
bool call_disconnect = false; bool call_disconnect;
{ {
unique_lock connections_lock(this->connections_lock); unique_lock connections_lock{this->connections_mutex};
auto index = find(this->connections.begin(), this->connections.end(), connection); auto index = std::find(this->connections.begin(), this->connections.end(), connection);
if(index == this->connections.end()) return; if(index == this->connections.end()) {
return;
}
this->connections.erase(index); this->connections.erase(index);
call_disconnect = this->connections.empty(); call_disconnect = this->connections.empty();
} }
auto dl = this->listener_disconnected; auto dl = this->listener_disconnected;
if(call_disconnect && dl) if(call_disconnect && dl) {
dl(this->disconnecting); dl(this->disconnecting);
}
} }
result MySQLManager::executeCommand(std::shared_ptr<CommandData> _ptr) { result MySQLManager::executeCommand(std::shared_ptr<CommandData> command_data) {
auto ptr = static_pointer_cast<MySQLCommand>(_ptr); auto mysql_data = static_pointer_cast<MySQLCommand>(command_data);
if(!ptr) { return {-1, "invalid command handle"}; } if(!mysql_data) {
return {"", -1, -1, "invalid command handle"};
}
std::lock_guard<threads::Mutex> lock(ptr->lock); std::lock_guard<threads::Mutex> lock(mysql_data->lock);
auto command = ptr->sql_command; auto command = mysql_data->sql_command;
auto variables = ptr->variables; auto variables = mysql_data->variables;
vector<variable> mapped_variables; vector<variable> mapped_variables;
if(!sql::mysql::evaluate_sql_query(command, variables, mapped_variables)) if(!sql::mysql::evaluate_sql_query(command, variables, mapped_variables)) {
return {ptr->sql_command, -1, "Could not map sqlite vars to mysql!"}; return {mysql_data->sql_command, -1, -1, "Could not map sqlite vars to mysql!"};
}
FreeGuard<BindMemory> bind_parameter_memory{nullptr}; FreeGuard<BindMemory> bind_parameter_memory{nullptr};
if(!sql::mysql::create_bind(bind_parameter_memory.ptr, mapped_variables)) if(!sql::mysql::create_bind(bind_parameter_memory.ptr, mapped_variables)) {
return {ptr->sql_command, -1, "Failed to allocate bind memory!"}; return {mysql_data->sql_command, -1, -1, "Failed to allocate bind memory!"};
}
ResultBind bind_result_data{0, nullptr, nullptr}; ResultBind bind_result_data{0, nullptr, nullptr};
auto connection = this->next_connection(); auto connection = this->next_connection();
if(!connection) return {ptr->sql_command, -1, "Could not get a valid connection!"}; if(!connection) {
return {mysql_data->sql_command, -1, -1, "Could not get a valid connection!"};
}
StatementGuard stmt_guard{mysql_stmt_init(connection->connection->handle)}; StatementGuard stmt_guard{mysql_stmt_init(connection->connection->handle)};
if(!stmt_guard.stmt) if(!stmt_guard.stmt) {
return {ptr->sql_command, -1, "failed to allocate statement"}; return {mysql_data->sql_command, -1, -1, "failed to allocate statement"};
}
if(mysql_stmt_prepare(stmt_guard.stmt, command.c_str(), command.length())) { if(mysql_stmt_prepare(stmt_guard.stmt, command.c_str(), command.length())) {
auto errc = mysql_stmt_errno(stmt_guard.stmt); auto errc = mysql_stmt_errno(stmt_guard.stmt);
if(errc == CR_SERVER_GONE_ERROR || errc == CR_SERVER_LOST || errc == CR_CONNECTION_ERROR) if(errc == CR_SERVER_GONE_ERROR || errc == CR_SERVER_LOST || errc == CR_CONNECTION_ERROR) {
this->connection_closed(connection->connection); this->connection_closed(connection->connection);
}
return {ptr->sql_command, -1, "failed to prepare statement: " + string(mysql_stmt_error(stmt_guard.stmt))}; return {mysql_data->sql_command, -1, -1, "failed to prepare statement: " + string(mysql_stmt_error(stmt_guard.stmt))};
} }
/* validate all parameters */ /* validate all parameters */
auto parameter_count = mysql_stmt_param_count(stmt_guard.stmt); auto parameter_count = mysql_stmt_param_count(stmt_guard.stmt);
if(parameter_count != mapped_variables.size()) if(parameter_count != mapped_variables.size()) {
return {ptr->sql_command, -1, "invalid parameter count. Statement contains " + to_string(parameter_count) + " parameters but only " + to_string(mapped_variables.size()) + " are given."}; return {mysql_data->sql_command, -1, -1, "invalid parameter count. Statement contains " + to_string(parameter_count) + " parameters but only " + to_string(mapped_variables.size()) + " are given."};
}
if(bind_parameter_memory.ptr) { if(bind_parameter_memory.ptr) {
if(mysql_stmt_bind_param(stmt_guard.stmt, (MYSQL_BIND*) bind_parameter_memory.ptr)) if(mysql_stmt_bind_param(stmt_guard.stmt, (MYSQL_BIND*) bind_parameter_memory.ptr)) {
return {ptr->sql_command, -1, "failed to bind parameters to statement: " + string(mysql_stmt_error(stmt_guard.stmt))}; return {mysql_data->sql_command, -1, -1, "failed to bind parameters to statement: " + string(mysql_stmt_error(stmt_guard.stmt))};
} else if(parameter_count > 0) }
return {ptr->sql_command, -1, "invalid parameter count. Statement contains " + to_string(parameter_count) + " parameters but only " + to_string(mapped_variables.size()) + " are given (bind nullptr)."}; } else if(parameter_count > 0) {
return {mysql_data->sql_command, -1, -1, "invalid parameter count. Statement contains " + to_string(parameter_count) + " parameters but only " + to_string(mapped_variables.size()) + " are given (bind nullptr)."};
}
if(mysql_stmt_execute(stmt_guard.stmt)) { if(mysql_stmt_execute(stmt_guard.stmt)) {
auto errc = mysql_stmt_errno(stmt_guard.stmt); auto errc = mysql_stmt_errno(stmt_guard.stmt);
if(errc == CR_SERVER_GONE_ERROR || errc == CR_SERVER_LOST || errc == CR_CONNECTION_ERROR) if(errc == CR_SERVER_GONE_ERROR || errc == CR_SERVER_LOST || errc == CR_CONNECTION_ERROR) {
this->connection_closed(connection->connection); this->connection_closed(connection->connection);
}
return {ptr->sql_command, -1, "failed to execute query statement: " + string(mysql_stmt_error(stmt_guard.stmt))}; return {mysql_data->sql_command, -1, -1, "failed to execute query statement: " + string(mysql_stmt_error(stmt_guard.stmt))};
} }
return result::success; auto insert_row_id = mysql_stmt_insert_id(stmt_guard.stmt);
return {mysql_data->sql_command, 0, (int64_t) insert_row_id, "success"};
} }
result MySQLManager::queryCommand(shared_ptr<CommandData> _ptr, const QueryCallback &fn) { result MySQLManager::queryCommand(shared_ptr<CommandData> command_data, const QueryCallback &fn) {
auto ptr = static_pointer_cast<MySQLCommand>(_ptr); auto mysql_data = static_pointer_cast<MySQLCommand>(command_data);
if(!ptr) { return {-1, "invalid command handle"}; } if(!mysql_data) {
return {"", -1, -1, "invalid command handle"};
}
std::lock_guard<threads::Mutex> lock(ptr->lock); std::lock_guard<threads::Mutex> lock(mysql_data->lock);
auto command = ptr->sql_command; auto command = mysql_data->sql_command;
auto variables = ptr->variables; auto variables = mysql_data->variables;
vector<variable> mapped_variables; vector<variable> mapped_variables;
if(!sql::mysql::evaluate_sql_query(command, variables, mapped_variables)) return {ptr->sql_command, -1, "Could not map sqlite vars to mysql!"}; if(!sql::mysql::evaluate_sql_query(command, variables, mapped_variables)) return {mysql_data->sql_command, -1, -1, "Could not map sqlite vars to mysql!"};
FreeGuard<BindMemory> bind_parameter_memory{nullptr}; FreeGuard<BindMemory> bind_parameter_memory{nullptr};
if(!sql::mysql::create_bind(bind_parameter_memory.ptr, mapped_variables)) return {ptr->sql_command, -1, "Failed to allocate bind memory!"}; if(!sql::mysql::create_bind(bind_parameter_memory.ptr, mapped_variables)) return {mysql_data->sql_command, -1, -1, "Failed to allocate bind memory!"};
ResultBind bind_result_data{0, nullptr, nullptr}; ResultBind bind_result_data{0, nullptr, nullptr};
auto connection = this->next_connection(); auto connection = this->next_connection();
if(!connection) return {ptr->sql_command, -1, "Could not get a valid connection!"}; if(!connection) return {mysql_data->sql_command, -1, -1, "Could not get a valid connection!"};
StatementGuard stmt_guard{mysql_stmt_init(connection->connection->handle)}; StatementGuard stmt_guard{mysql_stmt_init(connection->connection->handle)};
if(!stmt_guard.stmt) if(!stmt_guard.stmt)
return {ptr->sql_command, -1, "failed to allocate statement"}; return {mysql_data->sql_command, -1, -1, "failed to allocate statement"};
if(mysql_stmt_prepare(stmt_guard.stmt, command.c_str(), command.length())) { if(mysql_stmt_prepare(stmt_guard.stmt, command.c_str(), command.length())) {
auto errc = mysql_stmt_errno(stmt_guard.stmt); auto errc = mysql_stmt_errno(stmt_guard.stmt);
if(errc == CR_SERVER_GONE_ERROR || errc == CR_SERVER_LOST || errc == CR_CONNECTION_ERROR) if(errc == CR_SERVER_GONE_ERROR || errc == CR_SERVER_LOST || errc == CR_CONNECTION_ERROR)
this->connection_closed(connection->connection); this->connection_closed(connection->connection);
return {ptr->sql_command, -1, "failed to prepare statement: " + string(mysql_stmt_error(stmt_guard.stmt))}; return {mysql_data->sql_command, -1, -1, "failed to prepare statement: " + string(mysql_stmt_error(stmt_guard.stmt))};
} }
/* validate all parameters */ /* validate all parameters */
{ {
auto parameter_count = mysql_stmt_param_count(stmt_guard.stmt); auto parameter_count = mysql_stmt_param_count(stmt_guard.stmt);
if(parameter_count != mapped_variables.size()) if(parameter_count != mapped_variables.size())
return {ptr->sql_command, -1, "invalid parameter count. Statement contains " + to_string(parameter_count) + " parameters but only " + to_string(mapped_variables.size()) + " are given."}; return {mysql_data->sql_command, -1, -1, "invalid parameter count. Statement contains " + to_string(parameter_count) + " parameters but only " + to_string(mapped_variables.size()) + " are given."};
} }
if(bind_parameter_memory.ptr) { if(bind_parameter_memory.ptr) {
if(mysql_stmt_bind_param(stmt_guard.stmt, (MYSQL_BIND*) bind_parameter_memory.ptr)) if(mysql_stmt_bind_param(stmt_guard.stmt, (MYSQL_BIND*) bind_parameter_memory.ptr))
return {ptr->sql_command, -1, "failed to bind parameters to statement: " + string(mysql_stmt_error(stmt_guard.stmt))}; return {mysql_data->sql_command, -1, -1, "failed to bind parameters to statement: " + string(mysql_stmt_error(stmt_guard.stmt))};
} }
if(mysql_stmt_execute(stmt_guard.stmt)) { if(mysql_stmt_execute(stmt_guard.stmt)) {
@ -795,7 +814,7 @@ result MySQLManager::queryCommand(shared_ptr<CommandData> _ptr, const QueryCallb
if(errc == CR_SERVER_GONE_ERROR || errc == CR_SERVER_LOST || errc == CR_CONNECTION_ERROR) if(errc == CR_SERVER_GONE_ERROR || errc == CR_SERVER_LOST || errc == CR_CONNECTION_ERROR)
this->connection_closed(connection->connection); this->connection_closed(connection->connection);
return {ptr->sql_command, -1, "failed to execute query statement: " + string(mysql_stmt_error(stmt_guard.stmt))}; return {mysql_data->sql_command, -1, -1, "failed to execute query statement: " + string(mysql_stmt_error(stmt_guard.stmt))};
} }
//if(mysql_stmt_store_result(stmt_guard.stmt)) //if(mysql_stmt_store_result(stmt_guard.stmt))
@ -803,7 +822,7 @@ result MySQLManager::queryCommand(shared_ptr<CommandData> _ptr, const QueryCallb
ResultGuard result_guard{mysql_stmt_result_metadata(stmt_guard.stmt)}; ResultGuard result_guard{mysql_stmt_result_metadata(stmt_guard.stmt)};
if(!result_guard.result) if(!result_guard.result)
return {ptr->sql_command, -1, "failed to query result metadata: " + string(mysql_stmt_error(stmt_guard.stmt))}; return {mysql_data->sql_command, -1, -1, "failed to query result metadata: " + string(mysql_stmt_error(stmt_guard.stmt))};
auto field_count = mysql_num_fields(result_guard.result); auto field_count = mysql_num_fields(result_guard.result);
@ -813,13 +832,13 @@ result MySQLManager::queryCommand(shared_ptr<CommandData> _ptr, const QueryCallb
{ {
auto field_meta = mysql_fetch_fields(result_guard.result); auto field_meta = mysql_fetch_fields(result_guard.result);
if(!field_meta && field_count > 0) if(!field_meta && field_count > 0)
return {ptr->sql_command, -1, "failed to fetch field meta"}; return {mysql_data->sql_command, -1, -1, "failed to fetch field meta"};
if(!sql::mysql::create_result_bind(field_count, field_meta, bind_result_data)) if(!sql::mysql::create_result_bind(field_count, field_meta, bind_result_data))
return {ptr->sql_command, -1, "failed to allocate result buffer"}; return {mysql_data->sql_command, -1, -1, "failed to allocate result buffer"};
if(mysql_stmt_bind_result(stmt_guard.stmt, (MYSQL_BIND*) bind_result_data.memory)) if(mysql_stmt_bind_result(stmt_guard.stmt, (MYSQL_BIND*) bind_result_data.memory))
return {ptr->sql_command, -1, "failed to bind response buffer to statement: " + string(mysql_stmt_error(stmt_guard.stmt))}; return {mysql_data->sql_command, -1, -1, "failed to bind response buffer to statement: " + string(mysql_stmt_error(stmt_guard.stmt))};
for(size_t index = 0; index < field_count; index++) { for(size_t index = 0; index < field_count; index++) {
field_names.ptr[index] = field_meta[index].name; // field_meta cant be null because it has been checked above field_names.ptr[index] = field_meta[index].name; // field_meta cant be null because it has been checked above
@ -846,11 +865,11 @@ result MySQLManager::queryCommand(shared_ptr<CommandData> _ptr, const QueryCallb
if(errc == CR_SERVER_GONE_ERROR || errc == CR_SERVER_LOST || errc == CR_CONNECTION_ERROR) if(errc == CR_SERVER_GONE_ERROR || errc == CR_SERVER_LOST || errc == CR_CONNECTION_ERROR)
this->connection_closed(connection->connection); this->connection_closed(connection->connection);
return {ptr->sql_command, -1, "failed to fetch response row " + to_string(row_id) + ": " + string(mysql_stmt_error(stmt_guard.stmt))}; return {mysql_data->sql_command, -1, -1, "failed to fetch response row " + to_string(row_id) + ": " + string(mysql_stmt_error(stmt_guard.stmt))};
} else if(stmt_code == MYSQL_NO_DATA) } else if(stmt_code == MYSQL_NO_DATA)
; ;
else if(stmt_code == MYSQL_DATA_TRUNCATED) else if(stmt_code == MYSQL_DATA_TRUNCATED)
return {ptr->sql_command, -1, "response data has been truncated"}; return {mysql_data->sql_command, -1, -1, "response data has been truncated"};
} }
return result::success; return result::success;
} }

View File

@ -65,17 +65,17 @@ namespace sql::mysql {
protected: protected:
std::shared_ptr<CommandData> copyCommandData(std::shared_ptr<CommandData> ptr) override; std::shared_ptr<CommandData> copyCommandData(std::shared_ptr<CommandData> ptr) override;
std::shared_ptr<CommandData> allocateCommandData() override; std::shared_ptr<CommandData> allocateCommandData() override;
result executeCommand(std::shared_ptr<CommandData> ptr) override; result executeCommand(std::shared_ptr<CommandData> command_data) override;
result queryCommand(std::shared_ptr<CommandData> ptr, const QueryCallback &fn) override; result queryCommand(std::shared_ptr<CommandData> command_data, const QueryCallback &fn) override;
public: public:
std::unique_ptr<AcquiredConnection> next_connection(); std::unique_ptr<AcquiredConnection> next_connection();
void connection_closed(const std::shared_ptr<Connection>& /* connection */); void connection_closed(const std::shared_ptr<Connection>& /* connection */);
std::mutex connections_lock; std::mutex connections_mutex;
std::condition_variable connections_condition; std::condition_variable connections_condition;
std::deque<std::shared_ptr<Connection>> connections; std::deque<std::shared_ptr<Connection>> connections;
bool disconnecting = false; bool disconnecting{false};
}; };
} }

View File

@ -17,7 +17,7 @@ result SqliteManager::connect(const std::string &string) {
auto result = sqlite3_open(url.c_str(), &this->database); auto result = sqlite3_open(url.c_str(), &this->database);
if(!this->database) if(!this->database)
return {"connect", -1, "could not open database. Code: " + to_string(result)}; return {"connect", -1, -1, "could not open database. Code: " + to_string(result)};
return result::success; return result::success;
} }
@ -26,15 +26,17 @@ bool SqliteManager::connected() {
} }
result SqliteManager::disconnect() { result SqliteManager::disconnect() {
if(!this->database) if(!this->database) {
return {"disconnect", -1, "database not open"}; return {"disconnect", -1, -1, "database not open"};
}
this->pool->threads()->wait_for(); this->pool->threads()->wait_for();
auto result = sqlite3_close(this->database); auto result = sqlite3_close(this->database);
if(result == 0) { if(result == 0) {
this->database = nullptr; this->database = nullptr;
return result::success; return result::success;
}; };
return {"disconnect", -1, "Failed to close database. Code: " + to_string(result)}; return {"disconnect", -1, -1, "Failed to close database. Code: " + to_string(result)};
} }
std::shared_ptr<CommandData> SqliteManager::allocateCommandData() { std::shared_ptr<CommandData> SqliteManager::allocateCommandData() {
@ -104,8 +106,9 @@ result SqliteManager::queryCommand(std::shared_ptr<CommandData> _ptr, const Quer
sqlite3_reset(stmt.get()); sqlite3_reset(stmt.get());
} else { } else {
ptr->stmt = this->allocateStatement(ptr->sql_command); ptr->stmt = this->allocateStatement(ptr->sql_command);
if(!ptr->stmt) if(!ptr->stmt) {
return {_ptr->sql_command,1, sqlite3_errmsg(ptr->sqlHandle<SqliteManager>()->database)}; return {_ptr->sql_command, 1, -1, sqlite3_errmsg(ptr->sqlHandle<SqliteManager>()->database)};
}
stmt = ptr->stmt; stmt = ptr->stmt;
} }
@ -135,35 +138,42 @@ result SqliteManager::queryCommand(std::shared_ptr<CommandData> _ptr, const Quer
} }
} }
if(result != SQLITE_DONE && !userQuit) return {_ptr->sql_command,result, sqlite3_errstr(result)}; if(result != SQLITE_DONE && !userQuit) {
return {_ptr->sql_command,0, "success"}; return {_ptr->sql_command, result, -1, sqlite3_errstr(result)};
}
return {_ptr->sql_command,0, 0, "success"};
} }
result SqliteManager::executeCommand(std::shared_ptr<CommandData> _ptr) { result SqliteManager::executeCommand(std::shared_ptr<CommandData> command_data) {
auto ptr = static_pointer_cast<SqliteCommand>(_ptr); auto sql_command = static_pointer_cast<SqliteCommand>(command_data);
std::lock_guard<threads::Mutex> lock(ptr->lock); std::lock_guard<threads::Mutex> lock(sql_command->lock);
result res; result res{};
sqlite3_stmt* stmt; sqlite3_stmt* stmt{};
if(ptr->stmt){ if(sql_command->stmt){
stmt = ptr->stmt.get(); stmt = sql_command->stmt.get();
sqlite3_reset(stmt); sqlite3_reset(stmt);
} else { } else {
ptr->stmt = this->allocateStatement(ptr->sql_command); sql_command->stmt = this->allocateStatement(sql_command->sql_command);
if(!ptr->stmt) if(!sql_command->stmt) {
return {_ptr->sql_command,1, sqlite3_errmsg(ptr->sqlHandle<SqliteManager>()->database)}; return {sql_command->sql_command, 1, -1, sqlite3_errmsg(sql_command->sqlHandle<SqliteManager>()->database)};
stmt = ptr->stmt.get(); }
stmt = sql_command->stmt.get();
} }
int varIndex = 0; int variable_index{0};
for(const auto& var : ptr->variables) for(const auto& var : sql_command->variables) {
bindVariable(stmt, varIndex, var); bindVariable(stmt, variable_index, var);
}
int result = sqlite3_step(stmt); int result = sqlite3_step(stmt);
//logCritical(0, "Changes: {} SQL: {}", sqlite3_changes(this->database), ptr->sql_command); if(result == SQLITE_DONE) {
if(result == SQLITE_DONE) auto last_row = sqlite3_last_insert_rowid(this->database);
return {_ptr->sql_command,0, "success"}; return {sql_command->sql_command, 0, last_row, "success"};
if(result == SQLITE_ROW) return {_ptr->sql_command,-1, "query has a result"}; } else if(result == SQLITE_ROW) {
return {_ptr->sql_command, 1, sqlite3_errstr(result)}; return {sql_command->sql_command, -1, -1, "query has a result"};
} else {
return {sql_command->sql_command, 1, -1, sqlite3_errstr(result)};
}
} }

View File

@ -21,7 +21,7 @@ namespace sql {
protected: protected:
std::shared_ptr<CommandData> copyCommandData(std::shared_ptr<CommandData> ptr) override; std::shared_ptr<CommandData> copyCommandData(std::shared_ptr<CommandData> ptr) override;
std::shared_ptr<CommandData> allocateCommandData() override; std::shared_ptr<CommandData> allocateCommandData() override;
result executeCommand(std::shared_ptr<CommandData> ptr) override; result executeCommand(std::shared_ptr<CommandData> command_data) override;
result queryCommand(std::shared_ptr<CommandData> ptr, const QueryCallback&fn) override; result queryCommand(std::shared_ptr<CommandData> ptr, const QueryCallback&fn) override;
private: private: