Merge pull request #161 from addtheice/DatabaseInterface

Database interface
This commit is contained in:
Alex 2014-07-03 19:31:36 -07:00
commit 127682cc84
7 changed files with 334 additions and 2 deletions

View File

@ -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

View 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;
}

View 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

View 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
View 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

View File

@ -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;

View File

@ -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; }