Adding support to get the last inserted row
This commit is contained in:
parent
6e99fc1ab4
commit
539d94e724
@ -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 {
|
||||||
|
@ -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;
|
||||||
}
|
}
|
@ -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};
|
||||||
};
|
};
|
||||||
}
|
}
|
@ -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)};
|
||||||
|
}
|
||||||
}
|
}
|
@ -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:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user