mirror of
https://github.com/EQEmu/Server.git
synced 2026-03-25 12:42:25 +00:00
[Database] Add query multi statement execution support (#3414)
This commit is contained in:
parent
3200145d01
commit
b45e0e80b5
@ -13,6 +13,7 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <mysqld_error.h>
|
#include <mysqld_error.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include "strings.h"
|
||||||
|
|
||||||
#ifdef _WINDOWS
|
#ifdef _WINDOWS
|
||||||
#define snprintf _snprintf
|
#define snprintf _snprintf
|
||||||
@ -305,3 +306,92 @@ void DBcore::SetMutex(Mutex *mutex)
|
|||||||
|
|
||||||
DBcore::m_mutex = mutex;
|
DBcore::m_mutex = mutex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// executes multiple statements in one query
|
||||||
|
// do not use this in application logic
|
||||||
|
// this was built and maintained for database migrations only
|
||||||
|
MySQLRequestResult DBcore::QueryDatabaseMulti(const std::string &query)
|
||||||
|
{
|
||||||
|
SetMultiStatementsOn();
|
||||||
|
|
||||||
|
BenchTimer timer;
|
||||||
|
timer.reset();
|
||||||
|
|
||||||
|
LockMutex lock(m_mutex);
|
||||||
|
|
||||||
|
// Reconnect if we are not connected before hand.
|
||||||
|
if (pStatus != Connected) {
|
||||||
|
Open();
|
||||||
|
}
|
||||||
|
|
||||||
|
int status = mysql_real_query(mysql, query.c_str(), query.length());
|
||||||
|
if (status != 0) {
|
||||||
|
unsigned int error_number = mysql_errno(mysql);
|
||||||
|
|
||||||
|
if (error_number == CR_SERVER_GONE_ERROR) {
|
||||||
|
pStatus = Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// error logging
|
||||||
|
if (mysql_errno(mysql) > 0 && query.length() > 0 && mysql_errno(mysql) != 1065) {
|
||||||
|
std::string error_raw = fmt::format("{}", mysql_error(mysql));
|
||||||
|
std::string mysql_err = Strings::Trim(error_raw);
|
||||||
|
std::string clean_query = Strings::Replace(query, "\n", "");
|
||||||
|
LogMySQLQuery("[{}] ({}) query [{}]", mysql_err, mysql_errno(mysql), clean_query);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto result = MySQLRequestResult{};
|
||||||
|
|
||||||
|
int index = 0;
|
||||||
|
|
||||||
|
// there could be a query with a semicolon in the actual data, this is best effort for
|
||||||
|
// logging / display purposes
|
||||||
|
// rare that we see this when this is only used in DDL statements
|
||||||
|
auto pieces = Strings::Split(query, ";");
|
||||||
|
|
||||||
|
// process each statement result
|
||||||
|
do {
|
||||||
|
uint32 row_count = 0;
|
||||||
|
MYSQL_RES *res = mysql_store_result(mysql);
|
||||||
|
|
||||||
|
result = MySQLRequestResult(
|
||||||
|
res,
|
||||||
|
(uint32) mysql_affected_rows(mysql),
|
||||||
|
row_count,
|
||||||
|
(uint32) mysql_field_count(mysql),
|
||||||
|
(uint32) mysql_insert_id(mysql)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (pieces.size() >= index) {
|
||||||
|
auto piece = pieces[index];
|
||||||
|
LogMySQLQuery(
|
||||||
|
"{} -- ({} row{} affected) ({}s)",
|
||||||
|
piece,
|
||||||
|
result.RowsAffected(),
|
||||||
|
result.RowsAffected() == 1 ? "" : "s",
|
||||||
|
std::to_string(timer.elapsed())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res) {
|
||||||
|
row_count = (uint32) mysql_num_rows(res);
|
||||||
|
mysql_free_result(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
// more results? -1 = no, >0 = error, 0 = yes (keep looping)
|
||||||
|
if ((status = mysql_next_result(mysql)) > 0) {
|
||||||
|
if (mysql_errno(mysql) > 0) {
|
||||||
|
LogMySQLError("[{}] [{}]", mysql_errno(mysql), mysql_error(mysql));
|
||||||
|
}
|
||||||
|
|
||||||
|
// we handle errors elsewhere
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
} while (status == 0);
|
||||||
|
|
||||||
|
SetMultiStatementsOff();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|||||||
@ -25,6 +25,7 @@ public:
|
|||||||
eStatus GetStatus() { return pStatus; }
|
eStatus GetStatus() { return pStatus; }
|
||||||
MySQLRequestResult QueryDatabase(const char *query, uint32 querylen, bool retryOnFailureOnce = true);
|
MySQLRequestResult QueryDatabase(const char *query, uint32 querylen, bool retryOnFailureOnce = true);
|
||||||
MySQLRequestResult QueryDatabase(const std::string& query, bool retryOnFailureOnce = true);
|
MySQLRequestResult QueryDatabase(const std::string& query, bool retryOnFailureOnce = true);
|
||||||
|
MySQLRequestResult QueryDatabaseMulti(const std::string &query);
|
||||||
void TransactionBegin();
|
void TransactionBegin();
|
||||||
void TransactionCommit();
|
void TransactionCommit();
|
||||||
void TransactionRollback();
|
void TransactionRollback();
|
||||||
@ -77,8 +78,20 @@ private:
|
|||||||
uint32 pPort;
|
uint32 pPort;
|
||||||
bool pSSL;
|
bool pSSL;
|
||||||
|
|
||||||
|
// allows multiple queries to be executed within the same query
|
||||||
|
// do not use this under normal operation
|
||||||
|
// we use this during database migrations only currently
|
||||||
|
void SetMultiStatementsOn()
|
||||||
|
{
|
||||||
|
mysql_set_server_option(mysql, MYSQL_OPTION_MULTI_STATEMENTS_ON);
|
||||||
|
}
|
||||||
|
|
||||||
|
// disables multiple statements to be executed in one query
|
||||||
|
void SetMultiStatementsOff()
|
||||||
|
{
|
||||||
|
mysql_set_server_option(mysql, MYSQL_OPTION_MULTI_STATEMENTS_OFF);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user