mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-13 02:11:30 +00:00
Merge pull request #161 from addtheice/DatabaseInterface
Database interface
This commit is contained in:
commit
127682cc84
@ -39,6 +39,8 @@ SET(common_sources
|
||||
MiscFunctions.cpp
|
||||
moremath.cpp
|
||||
Mutex.cpp
|
||||
MySQLRequestResult.cpp
|
||||
MySQLRequestRow.cpp
|
||||
opcode_map.cpp
|
||||
opcodemgr.cpp
|
||||
packet_dump.cpp
|
||||
@ -149,6 +151,8 @@ SET(common_headers
|
||||
MiscFunctions.h
|
||||
moremath.h
|
||||
Mutex.h
|
||||
MySQLRequestResult.h
|
||||
MySQLRequestRow.h
|
||||
op_codes.h
|
||||
opcode_dispatch.h
|
||||
opcodemgr.h
|
||||
|
||||
103
common/MySQLRequestResult.cpp
Normal file
103
common/MySQLRequestResult.cpp
Normal file
@ -0,0 +1,103 @@
|
||||
#include "MySQLRequestResult.h"
|
||||
|
||||
|
||||
MySQLRequestResult::MySQLRequestResult()
|
||||
: m_CurrentRow(), m_OneBeyondRow()
|
||||
{
|
||||
ZeroOut();
|
||||
}
|
||||
|
||||
MySQLRequestResult::MySQLRequestResult(MYSQL_RES* result, uint32 rowsAffected, uint32 rowCount, uint32 columnCount, uint32 lastInsertedID, uint32 errorNumber, char *errorBuffer)
|
||||
: m_CurrentRow(result), m_OneBeyondRow()
|
||||
{
|
||||
if (errorBuffer != nullptr)
|
||||
m_Success = false;
|
||||
else if (errorBuffer == nullptr && result == nullptr)
|
||||
{
|
||||
m_Success = false;
|
||||
|
||||
#ifdef _EQDEBUG
|
||||
std::cout << "DB Query Error: No Result" << std::endl;
|
||||
#endif
|
||||
m_ErrorNumber = UINT_MAX;
|
||||
m_ErrorBuffer = new char[MYSQL_ERRMSG_SIZE];
|
||||
|
||||
strcpy(m_ErrorBuffer, "DBcore::RunQuery: No Result");
|
||||
}
|
||||
else
|
||||
m_Success = true;
|
||||
|
||||
m_Result = result;
|
||||
m_ErrorBuffer = errorBuffer;
|
||||
m_RowsAffected = rowsAffected;
|
||||
m_RowCount = rowCount;
|
||||
m_ColumnCount = columnCount;
|
||||
m_LastInsertedID = lastInsertedID;
|
||||
m_ErrorNumber = errorNumber;
|
||||
}
|
||||
|
||||
void MySQLRequestResult::FreeInternals()
|
||||
{
|
||||
safe_delete_array(m_ErrorBuffer);
|
||||
|
||||
if (m_Result != nullptr)
|
||||
mysql_free_result(m_Result);
|
||||
|
||||
ZeroOut();
|
||||
}
|
||||
|
||||
void MySQLRequestResult::ZeroOut()
|
||||
{
|
||||
m_Success = false;
|
||||
m_Result = nullptr;
|
||||
m_ErrorBuffer = nullptr;
|
||||
m_RowCount = 0;
|
||||
m_RowsAffected = 0;
|
||||
m_LastInsertedID = 0;
|
||||
}
|
||||
|
||||
MySQLRequestResult::~MySQLRequestResult()
|
||||
{
|
||||
FreeInternals();
|
||||
}
|
||||
|
||||
MySQLRequestResult::MySQLRequestResult(MySQLRequestResult&& moveItem)
|
||||
: m_CurrentRow(moveItem.m_CurrentRow), m_OneBeyondRow()
|
||||
{
|
||||
m_Result = moveItem.m_Result;
|
||||
m_ErrorBuffer = moveItem.m_ErrorBuffer;
|
||||
m_Success = moveItem.m_Success;
|
||||
m_RowCount = moveItem.m_RowCount;
|
||||
m_RowsAffected = moveItem.m_RowsAffected;
|
||||
m_LastInsertedID = moveItem.m_LastInsertedID;
|
||||
|
||||
// Keeps deconstructor from double freeing
|
||||
// pre move instance.
|
||||
moveItem.ZeroOut();
|
||||
}
|
||||
|
||||
MySQLRequestResult& MySQLRequestResult::operator=(MySQLRequestResult&& other)
|
||||
{
|
||||
// Assigning something to itself?
|
||||
// Silly! (but happens)
|
||||
if (this == &other)
|
||||
return *this;
|
||||
|
||||
FreeInternals();
|
||||
|
||||
m_Success = other.m_Success;
|
||||
|
||||
m_Result = other.m_Result;
|
||||
m_ErrorBuffer = other.m_ErrorBuffer;
|
||||
|
||||
m_RowCount = other.m_RowCount;
|
||||
m_RowsAffected = other.m_RowsAffected;
|
||||
m_LastInsertedID = other.m_LastInsertedID;
|
||||
m_CurrentRow = other.m_CurrentRow;
|
||||
m_OneBeyondRow = other.m_OneBeyondRow;
|
||||
|
||||
// Keeps deconstructor from double freeing
|
||||
// pre move instance.
|
||||
other.ZeroOut();
|
||||
return *this;
|
||||
}
|
||||
55
common/MySQLRequestResult.h
Normal file
55
common/MySQLRequestResult.h
Normal file
@ -0,0 +1,55 @@
|
||||
#ifndef MYSQL_REQUEST_RESULT_H
|
||||
#define MYSQL_REQUEST_RESULT_H
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#include <winsock.h>
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include <mysql.h>
|
||||
#include <../common/types.h>
|
||||
#include <../common/MySQLRequestRow.h>
|
||||
#include <string>
|
||||
|
||||
class MySQLRequestResult {
|
||||
private:
|
||||
MYSQL_RES* m_Result;
|
||||
char* m_ErrorBuffer;
|
||||
MySQLRequestRow m_CurrentRow;
|
||||
MySQLRequestRow m_OneBeyondRow;
|
||||
|
||||
bool m_Success;
|
||||
uint32 m_RowsAffected;
|
||||
uint32 m_RowCount;
|
||||
uint32 m_ColumnCount;
|
||||
uint32 m_LastInsertedID;
|
||||
uint32 m_ErrorNumber;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
MySQLRequestResult(MYSQL_RES* result, uint32 rowsAffected = 0, uint32 rowCount = 0, uint32 columnCount = 0, uint32 lastInsertedID = 0, uint32 errorNumber = 0, char *errorBuffer = nullptr);
|
||||
MySQLRequestResult();
|
||||
MySQLRequestResult(MySQLRequestResult&& moveItem);
|
||||
~MySQLRequestResult();
|
||||
|
||||
MySQLRequestResult& operator=(MySQLRequestResult&& other);
|
||||
|
||||
bool Success() const { return m_Success;}
|
||||
std::string ErrorMessage() const {return std::string(m_ErrorBuffer);}
|
||||
uint32 ErrorNumber() const {return m_ErrorNumber;}
|
||||
uint32 RowsAffected() const {return m_RowsAffected;}
|
||||
uint32 RowCount() const {return m_RowCount;}
|
||||
uint32 ColumnCount() const {return m_ColumnCount;}
|
||||
uint32 LastInsertedID() const {return m_LastInsertedID;}
|
||||
|
||||
MySQLRequestRow& begin() { return m_CurrentRow; }
|
||||
MySQLRequestRow& end() { return m_OneBeyondRow;}
|
||||
|
||||
private:
|
||||
void FreeInternals();
|
||||
void ZeroOut();
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
54
common/MySQLRequestRow.cpp
Normal file
54
common/MySQLRequestRow.cpp
Normal file
@ -0,0 +1,54 @@
|
||||
#include "MySQLRequestRow.h"
|
||||
|
||||
MySQLRequestRow::MySQLRequestRow(const MySQLRequestRow& row)
|
||||
: m_Result(row.m_Result), m_MySQLRow(row.m_MySQLRow)
|
||||
{
|
||||
}
|
||||
|
||||
MySQLRequestRow::MySQLRequestRow()
|
||||
: m_Result(nullptr), m_MySQLRow(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
MySQLRequestRow::MySQLRequestRow(MySQLRequestRow&& moveItem)
|
||||
{
|
||||
m_Result = moveItem.m_Result;
|
||||
m_MySQLRow = moveItem.m_MySQLRow;
|
||||
|
||||
moveItem.m_Result = nullptr;
|
||||
moveItem.m_MySQLRow = nullptr;
|
||||
}
|
||||
|
||||
MySQLRequestRow::MySQLRequestRow(MYSQL_RES *result)
|
||||
: m_Result(result), m_MySQLRow(mysql_fetch_row(m_Result))
|
||||
{
|
||||
}
|
||||
|
||||
MySQLRequestRow& MySQLRequestRow::operator++()
|
||||
{
|
||||
m_MySQLRow = mysql_fetch_row(m_Result);
|
||||
return *this;
|
||||
}
|
||||
|
||||
MySQLRequestRow MySQLRequestRow::operator++(int)
|
||||
{
|
||||
MySQLRequestRow tmp(*this);
|
||||
operator++();
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool MySQLRequestRow::operator==(const MySQLRequestRow& rhs)
|
||||
{
|
||||
return m_MySQLRow == rhs.m_MySQLRow;
|
||||
}
|
||||
|
||||
bool MySQLRequestRow::operator!=(const MySQLRequestRow& rhs)
|
||||
{
|
||||
return m_MySQLRow != rhs.m_MySQLRow;
|
||||
}
|
||||
|
||||
char* MySQLRequestRow::operator[](int index)
|
||||
{
|
||||
|
||||
return m_MySQLRow[index];
|
||||
}
|
||||
37
common/MySQLRequestRow.h
Normal file
37
common/MySQLRequestRow.h
Normal file
@ -0,0 +1,37 @@
|
||||
#ifndef MYSQL_REQUEST_ROW_H
|
||||
#define MYSQL_REQUEST_ROW_H
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#include <winsock.h>
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include <mysql.h>
|
||||
#include <iterator>
|
||||
#include <../common/types.h>
|
||||
|
||||
class MySQLRequestRow : public std::iterator<std::input_iterator_tag, MYSQL_ROW>
|
||||
{
|
||||
|
||||
private:
|
||||
MYSQL_RES* m_Result;
|
||||
MYSQL_ROW m_MySQLRow;
|
||||
|
||||
public:
|
||||
|
||||
MySQLRequestRow();
|
||||
MySQLRequestRow(MYSQL_RES *result);
|
||||
MySQLRequestRow(const MySQLRequestRow& row);
|
||||
MySQLRequestRow(MySQLRequestRow&& moveItem);
|
||||
MySQLRequestRow& operator++();
|
||||
MySQLRequestRow operator++(int);
|
||||
bool operator==(const MySQLRequestRow& rhs);
|
||||
bool operator!=(const MySQLRequestRow& rhs);
|
||||
|
||||
char* operator[](int index);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@ -58,6 +58,83 @@ void DBcore::ping() {
|
||||
MDatabase.unlock();
|
||||
}
|
||||
|
||||
MySQLRequestResult DBcore::QueryDatabase(const char* query, uint32 querylen, bool retryOnFailureOnce)
|
||||
{
|
||||
LockMutex lock(&MDatabase);
|
||||
|
||||
// Reconnect if we are not connected before hand.
|
||||
if (pStatus != Connected)
|
||||
Open();
|
||||
|
||||
// request query. != 0 indicates some kind of error.
|
||||
if (mysql_real_query(&mysql, query, querylen) != 0)
|
||||
{
|
||||
unsigned int errorNumber = mysql_errno(&mysql);
|
||||
|
||||
if (errorNumber == CR_SERVER_GONE_ERROR)
|
||||
pStatus = Error;
|
||||
|
||||
// error appears to be a disconnect error, may need to try again.
|
||||
if (errorNumber == CR_SERVER_LOST || errorNumber == CR_SERVER_GONE_ERROR)
|
||||
{
|
||||
|
||||
if (retryOnFailureOnce)
|
||||
{
|
||||
std::cout << "Database Error: Lost connection, attempting to recover...." << std::endl;
|
||||
MySQLRequestResult requestResult = QueryDatabase(query, querylen, false);
|
||||
|
||||
if (requestResult.Success())
|
||||
{
|
||||
std::cout << "Reconnection to database successful." << std::endl;
|
||||
return requestResult;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pStatus = Error;
|
||||
|
||||
char *errorBuffer = new char[MYSQL_ERRMSG_SIZE];
|
||||
|
||||
snprintf(errorBuffer, MYSQL_ERRMSG_SIZE, "#%i: %s", mysql_errno(&mysql), mysql_error(&mysql));
|
||||
|
||||
std::cout << "DB Query Error #" << mysql_errno(&mysql) << ": " << mysql_error(&mysql) << std::endl;
|
||||
|
||||
return MySQLRequestResult(nullptr, 0, 0, 0, 0, (uint32)mysql_errno(&mysql), errorBuffer);
|
||||
}
|
||||
|
||||
char *errorBuffer = new char[MYSQL_ERRMSG_SIZE];
|
||||
snprintf(errorBuffer, MYSQL_ERRMSG_SIZE, "#%i: %s", mysql_errno(&mysql), mysql_error(&mysql));
|
||||
|
||||
#ifdef _EQDEBUG
|
||||
std::cout << "DB Query Error #" << mysql_errno(&mysql) << ": " << mysql_error(&mysql) << std::endl;
|
||||
#endif
|
||||
return MySQLRequestResult(nullptr, 0, 0, 0, 0, mysql_errno(&mysql),errorBuffer);
|
||||
|
||||
}
|
||||
|
||||
// successful query. get results.
|
||||
MYSQL_RES* res = mysql_store_result(&mysql);
|
||||
MySQLRequestResult requestResult(res, (uint32)mysql_affected_rows(&mysql), (uint32)mysql_num_rows(res), (uint32)mysql_field_count(&mysql), (uint32)mysql_insert_id(&mysql));
|
||||
|
||||
|
||||
#if DEBUG_MYSQL_QUERIES >= 1
|
||||
if (requestResult.Success())
|
||||
{
|
||||
std::cout << "query successful";
|
||||
if (requestResult.Result())
|
||||
std::cout << ", " << (int) mysql_num_rows(requestResult.Result()) << " rows returned";
|
||||
|
||||
std::cout << ", " << requestResult.RowCount() << " rows affected";
|
||||
std::cout<< std::endl;
|
||||
}
|
||||
else {
|
||||
std::cout << "QUERY: query FAILED" << std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
return requestResult;
|
||||
}
|
||||
|
||||
bool DBcore::RunQuery(const char* query, uint32 querylen, char* errbuf, MYSQL_RES** result, uint32* affected_rows, uint32* last_insert_id, uint32* errnum, bool retry) {
|
||||
if (errnum)
|
||||
*errnum = 0;
|
||||
@ -111,7 +188,7 @@ bool DBcore::RunQuery(const char* query, uint32 querylen, char* errbuf, MYSQL_RE
|
||||
if (affected_rows)
|
||||
*affected_rows = mysql_affected_rows(&mysql);
|
||||
if (last_insert_id)
|
||||
*last_insert_id = mysql_insert_id(&mysql);
|
||||
*last_insert_id = (uint32)mysql_insert_id(&mysql);
|
||||
if (result) {
|
||||
if (*result) {
|
||||
ret = true;
|
||||
|
||||
@ -4,8 +4,8 @@
|
||||
#ifdef _WINDOWS
|
||||
#include <winsock.h>
|
||||
#include <windows.h>
|
||||
//#include <winsock.h>
|
||||
#endif
|
||||
|
||||
#include <mysql.h>
|
||||
#include "../common/types.h"
|
||||
#include "../common/Mutex.h"
|
||||
@ -13,6 +13,7 @@
|
||||
#include "../common/queue.h"
|
||||
#include "../common/timer.h"
|
||||
#include "../common/Condition.h"
|
||||
#include "../common/MySQLRequestResult.h"
|
||||
|
||||
class DBcore {
|
||||
public:
|
||||
@ -22,6 +23,7 @@ public:
|
||||
~DBcore();
|
||||
eStatus GetStatus() { return pStatus; }
|
||||
bool RunQuery(const char* query, uint32 querylen, char* errbuf = 0, MYSQL_RES** result = 0, uint32* affected_rows = 0, uint32* last_insert_id = 0, uint32* errnum = 0, bool retry = true);
|
||||
MySQLRequestResult QueryDatabase(const char* query, uint32 querylen, bool retryOnFailureOnce = true);
|
||||
uint32 DoEscapeString(char* tobuf, const char* frombuf, uint32 fromlen);
|
||||
void ping();
|
||||
MYSQL* getMySQL(){ return &mysql; }
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user