2010-08-11 15:23:10 +02:00
|
|
|
// ***************************************************************************
|
|
|
|
|
//
|
|
|
|
|
// Reality - The Matrix Online Server Emulator
|
2009-08-11 12:17:38 +00:00
|
|
|
// Copyright (C) 2006-2010 Rajko Stojadinovic
|
2010-08-11 15:23:10 +02:00
|
|
|
// http://mxoemu.info
|
2009-08-11 12:17:38 +00:00
|
|
|
//
|
2010-08-11 15:23:10 +02:00
|
|
|
// ---------------------------------------------------------------------------
|
2009-08-11 12:17:38 +00:00
|
|
|
//
|
2010-08-11 15:23:10 +02:00
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
|
|
|
// it under the terms of the GNU Affero General Public License as
|
|
|
|
|
// published by the Free Software Foundation, either version 3 of the
|
|
|
|
|
// License, or (at your option) any later version.
|
2009-08-11 12:17:38 +00:00
|
|
|
//
|
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
2010-08-11 15:23:10 +02:00
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
// GNU Affero General Public License for more details.
|
2009-08-11 12:17:38 +00:00
|
|
|
//
|
2010-08-11 15:23:10 +02:00
|
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
|
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
2009-08-11 12:17:38 +00:00
|
|
|
//
|
2010-08-11 15:23:10 +02:00
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
// ***************************************************************************
|
2009-08-11 12:17:38 +00:00
|
|
|
|
|
|
|
|
#include "DatabaseEnv.h"
|
|
|
|
|
#include "../Log.h"
|
|
|
|
|
#include "../Util.h"
|
|
|
|
|
#include "../Threading/Threading.h"
|
|
|
|
|
|
|
|
|
|
SQLCallbackBase::~SQLCallbackBase()
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Database::Database() : ThreadContext()
|
|
|
|
|
{
|
|
|
|
|
_counter=0;
|
|
|
|
|
ThreadRunning = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Database::~Database()
|
|
|
|
|
{
|
2010-02-17 07:17:06 +00:00
|
|
|
Shutdown();
|
2009-08-11 12:17:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Database::Initialize(const char* Hostname, unsigned int port, const char* Username, const char* Password, const char* DatabaseName, uint32 ConnectionCount, uint32 BufferSize)
|
|
|
|
|
{
|
|
|
|
|
uint32 i;
|
|
|
|
|
MYSQL * temp, * temp2;
|
|
|
|
|
my_bool my_true = true;
|
|
|
|
|
|
|
|
|
|
mHostname = string(Hostname);
|
|
|
|
|
mUsername = string(Username);
|
|
|
|
|
mPassword = string(Password);
|
|
|
|
|
mDatabaseName = string(DatabaseName);
|
|
|
|
|
|
2010-02-13 14:32:04 +00:00
|
|
|
INFO_LOG(format("MySQLDatabase Connecting to `%1%`, database `%2%`...") % Hostname % DatabaseName);
|
2009-08-11 12:17:38 +00:00
|
|
|
|
|
|
|
|
for( i = 0; i < ConnectionCount; ++i )
|
|
|
|
|
{
|
|
|
|
|
temp = mysql_init( NULL );
|
|
|
|
|
if(mysql_options(temp, MYSQL_SET_CHARSET_NAME, "utf8"))
|
|
|
|
|
WARNING_LOG("MySQLDatabase Could not set utf8 character set.");
|
|
|
|
|
|
|
|
|
|
if (mysql_options(temp, MYSQL_OPT_RECONNECT, &my_true))
|
|
|
|
|
WARNING_LOG("MYSQL_OPT_RECONNECT could not be set, connection drops may occur but will be counteracted.");
|
|
|
|
|
|
|
|
|
|
temp2 = mysql_real_connect( temp, Hostname, Username, Password, DatabaseName, port, NULL, 0 );
|
|
|
|
|
if( temp2 == NULL )
|
|
|
|
|
{
|
2010-02-13 14:32:04 +00:00
|
|
|
CRITICAL_LOG(format("MySQLDatabase Connection failed due to: `%1%`") % mysql_error( temp ) );
|
2009-08-11 12:17:38 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2010-02-17 07:17:06 +00:00
|
|
|
m_connections.push_back(DatabaseConnection(temp2));
|
2009-08-11 12:17:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Spawn Database thread
|
|
|
|
|
ThreadPool.ExecuteTask(this);
|
|
|
|
|
|
|
|
|
|
// launch the query thread
|
|
|
|
|
qt = new QueryThread(this);
|
|
|
|
|
ThreadPool.ExecuteTask(qt);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2010-02-17 07:17:06 +00:00
|
|
|
DatabaseConnection &Database::GetFreeConnection()
|
2009-08-11 12:17:38 +00:00
|
|
|
{
|
|
|
|
|
uint32 i = 0;
|
|
|
|
|
for(;;)
|
|
|
|
|
{
|
2010-02-17 07:17:06 +00:00
|
|
|
DatabaseConnection &con = m_connections[ ((i++) % m_connections.size()) ];
|
|
|
|
|
if(con.Busy.AttemptAcquire())
|
2009-08-11 12:17:38 +00:00
|
|
|
return con;
|
|
|
|
|
|
|
|
|
|
// sleep every 20 iterations, otherwise this can cause 100% cpu if the db link goes dead
|
|
|
|
|
if( !(i % 20) )
|
|
|
|
|
{
|
|
|
|
|
Sleep(10);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// shouldn't be reached
|
2010-02-17 07:17:06 +00:00
|
|
|
throw(exception());
|
2009-08-11 12:17:38 +00:00
|
|
|
}
|
|
|
|
|
|
2010-02-13 14:32:04 +00:00
|
|
|
QueryResult *Database::Query( string QueryString )
|
2009-08-11 12:17:38 +00:00
|
|
|
{
|
|
|
|
|
// Send the query
|
|
|
|
|
QueryResult * qResult = NULL;
|
2010-02-17 07:17:06 +00:00
|
|
|
DatabaseConnection &con = GetFreeConnection();
|
2009-08-11 12:17:38 +00:00
|
|
|
|
2010-02-13 14:32:04 +00:00
|
|
|
if( _SendQuery( con, QueryString.c_str(), false ) )
|
2009-08-11 12:17:38 +00:00
|
|
|
qResult = _StoreQueryResult( con );
|
|
|
|
|
|
2010-02-17 07:17:06 +00:00
|
|
|
con.Busy.Release();
|
2009-08-11 12:17:38 +00:00
|
|
|
return qResult;
|
|
|
|
|
}
|
|
|
|
|
|
2010-02-17 07:17:06 +00:00
|
|
|
QueryResult * Database::FQuery( string QueryString, DatabaseConnection &con)
|
2009-08-11 12:17:38 +00:00
|
|
|
{
|
|
|
|
|
// Send the query
|
|
|
|
|
QueryResult * qResult = NULL;
|
2010-02-13 14:32:04 +00:00
|
|
|
if( _SendQuery( con, QueryString.c_str(), false ) )
|
2009-08-11 12:17:38 +00:00
|
|
|
qResult = _StoreQueryResult( con );
|
|
|
|
|
|
|
|
|
|
return qResult;
|
|
|
|
|
}
|
|
|
|
|
|
2010-02-17 07:17:06 +00:00
|
|
|
void Database::FWaitExecute( string QueryString, DatabaseConnection &con)
|
2009-08-11 12:17:38 +00:00
|
|
|
{
|
|
|
|
|
// Send the query
|
2010-02-13 14:32:04 +00:00
|
|
|
_SendQuery( con, QueryString.c_str(), false );
|
2009-08-11 12:17:38 +00:00
|
|
|
}
|
|
|
|
|
|
2010-02-13 14:32:04 +00:00
|
|
|
void QueryBuffer::AddQuery(string fmt)
|
2009-08-11 12:17:38 +00:00
|
|
|
{
|
2010-02-16 12:08:42 +00:00
|
|
|
queries.push_back(fmt);
|
2009-08-11 12:17:38 +00:00
|
|
|
}
|
|
|
|
|
|
2010-02-17 07:17:06 +00:00
|
|
|
void Database::PerformQueryBuffer(QueryBuffer * b, DatabaseConnection &con)
|
|
|
|
|
{
|
|
|
|
|
if(!b->queries.size())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
while (b->queries.size() > 0)
|
|
|
|
|
{
|
|
|
|
|
string &currQuery = b->queries.front();
|
|
|
|
|
_SendQuery(con, currQuery.c_str(), false);
|
|
|
|
|
b->queries.pop_front();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Database::PerformQueryBuffer(QueryBuffer * b)
|
2009-08-11 12:17:38 +00:00
|
|
|
{
|
|
|
|
|
if(!b->queries.size())
|
|
|
|
|
return;
|
|
|
|
|
|
2010-02-17 07:17:06 +00:00
|
|
|
DatabaseConnection &con = GetFreeConnection();
|
2009-08-11 12:17:38 +00:00
|
|
|
|
2010-02-16 12:08:42 +00:00
|
|
|
while (b->queries.size() > 0)
|
2009-08-11 12:17:38 +00:00
|
|
|
{
|
2010-02-16 12:08:42 +00:00
|
|
|
string &currQuery = b->queries.front();
|
|
|
|
|
_SendQuery(con, currQuery.c_str(), false);
|
|
|
|
|
b->queries.pop_front();
|
2009-08-11 12:17:38 +00:00
|
|
|
}
|
|
|
|
|
|
2010-02-17 07:17:06 +00:00
|
|
|
con.Busy.Release();
|
2009-08-11 12:17:38 +00:00
|
|
|
}
|
|
|
|
|
|
2010-02-17 07:17:06 +00:00
|
|
|
|
2010-02-13 14:32:04 +00:00
|
|
|
bool Database::Execute( string QueryString)
|
2009-08-11 12:17:38 +00:00
|
|
|
{
|
|
|
|
|
if(!ThreadRunning)
|
2010-02-13 14:32:04 +00:00
|
|
|
return WaitExecute(QueryString);
|
2009-08-11 12:17:38 +00:00
|
|
|
|
2010-02-16 12:08:42 +00:00
|
|
|
queries_queue.push(new string(QueryString));
|
2009-08-11 12:17:38 +00:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//this will wait for completion
|
2010-02-13 14:32:04 +00:00
|
|
|
bool Database::WaitExecute( string QueryString)
|
2009-08-11 12:17:38 +00:00
|
|
|
{
|
2010-02-17 07:17:06 +00:00
|
|
|
DatabaseConnection &con = GetFreeConnection();
|
2010-02-13 14:32:04 +00:00
|
|
|
bool Result = _SendQuery(con, QueryString.c_str(), false);
|
2010-02-17 07:17:06 +00:00
|
|
|
con.Busy.Release();
|
2009-08-11 12:17:38 +00:00
|
|
|
return Result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Database::run()
|
|
|
|
|
{
|
|
|
|
|
SetThreadName("Database Executor");
|
|
|
|
|
ThreadRunning = true;
|
2010-02-16 12:08:42 +00:00
|
|
|
string *query = queries_queue.pop();
|
2010-02-17 07:17:06 +00:00
|
|
|
DatabaseConnection &con = GetFreeConnection();
|
2009-08-11 12:17:38 +00:00
|
|
|
while(query)
|
|
|
|
|
{
|
2010-02-16 12:08:42 +00:00
|
|
|
_SendQuery( con, query->c_str(), false );
|
|
|
|
|
delete query;
|
2009-08-11 12:17:38 +00:00
|
|
|
if(!m_threadRunning)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
query = queries_queue.pop();
|
|
|
|
|
}
|
|
|
|
|
|
2010-02-17 07:17:06 +00:00
|
|
|
con.Busy.Release();
|
2009-08-11 12:17:38 +00:00
|
|
|
|
|
|
|
|
if(queries_queue.get_size() > 0)
|
|
|
|
|
{
|
|
|
|
|
// execute all the remaining queries
|
|
|
|
|
query = queries_queue.pop_nowait();
|
|
|
|
|
while(query)
|
|
|
|
|
{
|
2010-02-17 07:17:06 +00:00
|
|
|
DatabaseConnection &con = GetFreeConnection();
|
2010-02-16 12:08:42 +00:00
|
|
|
_SendQuery( con, query->c_str(), false );
|
2010-02-17 07:17:06 +00:00
|
|
|
con.Busy.Release();
|
2010-02-16 12:08:42 +00:00
|
|
|
delete query;
|
2009-08-11 12:17:38 +00:00
|
|
|
query=queries_queue.pop_nowait();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ThreadRunning = false;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2010-02-13 14:32:04 +00:00
|
|
|
void AsyncQuery::AddQuery( string fmt )
|
2009-08-11 12:17:38 +00:00
|
|
|
{
|
|
|
|
|
AsyncQueryResult res;
|
|
|
|
|
res.query = NULL;
|
|
|
|
|
res.result = NULL;
|
2010-08-10 19:11:15 +02:00
|
|
|
size_t len = fmt.length();
|
2010-02-13 14:32:04 +00:00
|
|
|
if(len>0)
|
2009-08-11 12:17:38 +00:00
|
|
|
{
|
|
|
|
|
res.query = new char[len+1];
|
|
|
|
|
res.query[len] = 0;
|
2010-02-13 14:32:04 +00:00
|
|
|
memcpy(res.query, fmt.c_str(), len);
|
2009-08-11 12:17:38 +00:00
|
|
|
queries.push_back(res);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AsyncQuery::Perform()
|
|
|
|
|
{
|
2010-02-17 07:17:06 +00:00
|
|
|
DatabaseConnection &conn = db->GetFreeConnection();
|
2009-08-11 12:17:38 +00:00
|
|
|
for(vector<AsyncQueryResult>::iterator itr = queries.begin(); itr != queries.end(); ++itr)
|
|
|
|
|
itr->result = db->FQuery(itr->query, conn);
|
|
|
|
|
|
2010-02-17 07:17:06 +00:00
|
|
|
conn.Busy.Release();
|
2009-08-11 12:17:38 +00:00
|
|
|
func->run(queries);
|
|
|
|
|
|
|
|
|
|
delete this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AsyncQuery::~AsyncQuery()
|
|
|
|
|
{
|
|
|
|
|
delete func;
|
|
|
|
|
for(vector<AsyncQueryResult>::iterator itr = queries.begin(); itr != queries.end(); ++itr)
|
|
|
|
|
{
|
|
|
|
|
if(itr->result)
|
|
|
|
|
delete itr->result;
|
|
|
|
|
|
|
|
|
|
delete[] itr->query;
|
|
|
|
|
}
|
|
|
|
|
queries.clear();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Database::EndThreads()
|
|
|
|
|
{
|
|
|
|
|
Terminate();
|
|
|
|
|
while(ThreadRunning || qt)
|
|
|
|
|
{
|
|
|
|
|
if(query_buffer.get_size() == 0)
|
|
|
|
|
query_buffer.GetCond().Broadcast();
|
|
|
|
|
|
|
|
|
|
if(queries_queue.get_size() == 0)
|
|
|
|
|
queries_queue.GetCond().Broadcast();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Sleep(100);
|
|
|
|
|
if(!ThreadRunning)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
Sleep(1000);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool QueryThread::run( )
|
|
|
|
|
{
|
|
|
|
|
db->thread_proc_query( );
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QueryThread::~QueryThread()
|
|
|
|
|
{
|
|
|
|
|
db->qt = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Database::thread_proc_query()
|
|
|
|
|
{
|
|
|
|
|
QueryBuffer * q;
|
2010-02-17 07:17:06 +00:00
|
|
|
DatabaseConnection &con = GetFreeConnection();
|
2009-08-11 12:17:38 +00:00
|
|
|
|
|
|
|
|
q = query_buffer.pop( );
|
|
|
|
|
while( q != NULL )
|
|
|
|
|
{
|
|
|
|
|
PerformQueryBuffer( q, con );
|
|
|
|
|
delete q;
|
|
|
|
|
|
|
|
|
|
if( !m_threadRunning )
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
q = query_buffer.pop( );
|
|
|
|
|
}
|
|
|
|
|
|
2010-02-17 07:17:06 +00:00
|
|
|
con.Busy.Release();
|
2009-08-11 12:17:38 +00:00
|
|
|
|
|
|
|
|
// kill any queries
|
|
|
|
|
q = query_buffer.pop_nowait( );
|
|
|
|
|
while( q != NULL )
|
|
|
|
|
{
|
2010-02-17 07:17:06 +00:00
|
|
|
PerformQueryBuffer( q );
|
2009-08-11 12:17:38 +00:00
|
|
|
delete q;
|
|
|
|
|
|
|
|
|
|
q = query_buffer.pop_nowait( );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Database::QueueAsyncQuery(AsyncQuery * query)
|
|
|
|
|
{
|
|
|
|
|
query->db = this;
|
|
|
|
|
/*if(qt == NULL)
|
|
|
|
|
{
|
|
|
|
|
query->Perform();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
qqueries_queue.push(query);*/
|
|
|
|
|
query->Perform();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Database::AddQueryBuffer(QueryBuffer * b)
|
|
|
|
|
{
|
|
|
|
|
if( qt != NULL )
|
|
|
|
|
query_buffer.push( b );
|
|
|
|
|
else
|
|
|
|
|
{
|
2010-02-17 07:17:06 +00:00
|
|
|
PerformQueryBuffer( b );
|
2009-08-11 12:17:38 +00:00
|
|
|
delete b;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Database::FreeQueryResult(QueryResult * p)
|
|
|
|
|
{
|
|
|
|
|
delete p;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string Database::EscapeString(std::string Escape)
|
|
|
|
|
{
|
|
|
|
|
char a2[16384] = {0};
|
|
|
|
|
|
2010-02-17 07:17:06 +00:00
|
|
|
DatabaseConnection &con = GetFreeConnection();
|
2009-08-11 12:17:38 +00:00
|
|
|
const char * ret;
|
2010-02-17 07:17:06 +00:00
|
|
|
if(mysql_real_escape_string(con.conn, a2, Escape.c_str(), (unsigned long)Escape.length()) == 0)
|
2009-08-11 12:17:38 +00:00
|
|
|
ret = Escape.c_str();
|
|
|
|
|
else
|
|
|
|
|
ret = a2;
|
|
|
|
|
|
2010-02-17 07:17:06 +00:00
|
|
|
con.Busy.Release();
|
2009-08-11 12:17:38 +00:00
|
|
|
return string(ret);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Database::EscapeLongString(const char * str, uint32 len, stringstream& out)
|
|
|
|
|
{
|
|
|
|
|
char a2[65536*3] = {0};
|
|
|
|
|
|
2010-02-17 07:17:06 +00:00
|
|
|
DatabaseConnection &con = GetFreeConnection();
|
2009-08-11 12:17:38 +00:00
|
|
|
const char * ret;
|
2010-02-17 07:17:06 +00:00
|
|
|
if(mysql_real_escape_string(con.conn, a2, str, (unsigned long)len) == 0)
|
2009-08-11 12:17:38 +00:00
|
|
|
ret = str;
|
|
|
|
|
else
|
|
|
|
|
ret = a2;
|
|
|
|
|
|
|
|
|
|
out.write(a2, (std::streamsize)strlen(a2));
|
2010-02-17 07:17:06 +00:00
|
|
|
con.Busy.Release();
|
2009-08-11 12:17:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string Database::EscapeString(const char * esc, DatabaseConnection * con)
|
|
|
|
|
{
|
|
|
|
|
char a2[16384] = {0};
|
|
|
|
|
const char * ret;
|
|
|
|
|
if(mysql_real_escape_string(con->conn, a2, (char*)esc, (unsigned long)strlen(esc)) == 0)
|
|
|
|
|
ret = esc;
|
|
|
|
|
else
|
|
|
|
|
ret = a2;
|
|
|
|
|
|
|
|
|
|
return string(ret);
|
|
|
|
|
}
|
|
|
|
|
|
2010-02-17 07:17:06 +00:00
|
|
|
bool Database::_SendQuery(DatabaseConnection &con, const char* Sql, bool Self)
|
2009-08-11 12:17:38 +00:00
|
|
|
{
|
|
|
|
|
//dunno what it does ...leaving untouched
|
2010-02-17 07:17:06 +00:00
|
|
|
int result = mysql_query(con.conn, Sql);
|
2009-08-11 12:17:38 +00:00
|
|
|
if(result > 0)
|
|
|
|
|
{
|
2010-02-17 07:17:06 +00:00
|
|
|
if( Self == false && _HandleError(con, mysql_errno( con.conn ) ) )
|
2009-08-11 12:17:38 +00:00
|
|
|
{
|
|
|
|
|
// Re-send the query, the connection was successful.
|
|
|
|
|
// The true on the end will prevent an endless loop here, as it will
|
|
|
|
|
// stop after sending the query twice.
|
|
|
|
|
result = _SendQuery(con, Sql, true);
|
|
|
|
|
}
|
|
|
|
|
else
|
2010-02-17 07:17:06 +00:00
|
|
|
ERROR_LOG(format("Sql query failed due to [%1%], Query: [%2%]\n") % mysql_error( con.conn ) % Sql);
|
2009-08-11 12:17:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (result == 0 ? true : false);
|
|
|
|
|
}
|
|
|
|
|
|
2010-02-17 07:17:06 +00:00
|
|
|
bool Database::_HandleError(DatabaseConnection &con, uint32 ErrorNumber)
|
2009-08-11 12:17:38 +00:00
|
|
|
{
|
|
|
|
|
// Handle errors that should cause a reconnect to the Database.
|
|
|
|
|
switch(ErrorNumber)
|
|
|
|
|
{
|
|
|
|
|
case 2006: // Mysql server has gone away
|
|
|
|
|
case 2008: // Client ran out of memory
|
|
|
|
|
case 2013: // Lost connection to sql server during query
|
|
|
|
|
case 2055: // Lost connection to sql server - system error
|
|
|
|
|
{
|
|
|
|
|
// Let's instruct a reconnect to the db when we encounter these errors.
|
|
|
|
|
return _Reconnect( con );
|
|
|
|
|
}break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QueryResult::QueryResult(MYSQL_RES *res, uint32 fields, uint32 rows) : mResult(res), mFieldCount(fields), mRowCount(rows)
|
|
|
|
|
{
|
|
|
|
|
mCurrentRow = new Field[fields];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QueryResult::~QueryResult()
|
|
|
|
|
{
|
|
|
|
|
mysql_free_result(mResult);
|
|
|
|
|
delete [] mCurrentRow;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool QueryResult::NextRow()
|
|
|
|
|
{
|
|
|
|
|
MYSQL_ROW row = mysql_fetch_row(mResult);
|
|
|
|
|
if(row == NULL)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
for(uint32 i = 0; i < mFieldCount; ++i)
|
|
|
|
|
mCurrentRow[i].SetValue(row[i]);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2010-02-17 07:17:06 +00:00
|
|
|
QueryResult * Database::_StoreQueryResult(DatabaseConnection &con)
|
2009-08-11 12:17:38 +00:00
|
|
|
{
|
|
|
|
|
QueryResult *res;
|
2010-02-17 07:17:06 +00:00
|
|
|
MYSQL_RES * pRes = mysql_store_result( con.conn );
|
|
|
|
|
uint32 uRows = (uint32)mysql_affected_rows( con.conn );
|
|
|
|
|
uint32 uFields = (uint32)mysql_field_count( con.conn );
|
2009-08-11 12:17:38 +00:00
|
|
|
|
|
|
|
|
if( uRows == 0 || uFields == 0 || pRes == 0 )
|
|
|
|
|
{
|
|
|
|
|
if( pRes != NULL )
|
|
|
|
|
mysql_free_result( pRes );
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
res = new QueryResult( pRes, uFields, uRows );
|
|
|
|
|
res->NextRow();
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
2010-02-17 07:17:06 +00:00
|
|
|
bool Database::_Reconnect(DatabaseConnection &conn)
|
2009-08-11 12:17:38 +00:00
|
|
|
{
|
|
|
|
|
MYSQL * temp, *temp2;
|
|
|
|
|
|
|
|
|
|
temp = mysql_init( NULL );
|
|
|
|
|
temp2 = mysql_real_connect( temp, mHostname.c_str(), mUsername.c_str(), mPassword.c_str(), mDatabaseName.c_str(), mPort, NULL , 0 );
|
|
|
|
|
if( temp2 == NULL )
|
|
|
|
|
{
|
2010-02-13 14:32:04 +00:00
|
|
|
CRITICAL_LOG(format("Could not reconnect to database because of `%1%`") % mysql_error( temp ) );
|
2009-08-11 12:17:38 +00:00
|
|
|
mysql_close( temp );
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2010-02-17 07:17:06 +00:00
|
|
|
if( conn.conn != NULL )
|
|
|
|
|
mysql_close( conn.conn );
|
2009-08-11 12:17:38 +00:00
|
|
|
|
2010-02-17 07:17:06 +00:00
|
|
|
conn.conn = temp;
|
2009-08-11 12:17:38 +00:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Database::CleanupLibs()
|
|
|
|
|
{
|
|
|
|
|
mysql_library_end();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Database *Database::Create()
|
|
|
|
|
{
|
|
|
|
|
return new Database();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Database::Shutdown()
|
|
|
|
|
{
|
2010-02-17 07:17:06 +00:00
|
|
|
for(connectionsList::iterator it=m_connections.begin();it!=m_connections.end();++it)
|
2009-08-11 12:17:38 +00:00
|
|
|
{
|
2010-02-17 07:17:06 +00:00
|
|
|
if( it->conn != NULL )
|
2009-08-11 12:17:38 +00:00
|
|
|
{
|
2010-02-17 07:17:06 +00:00
|
|
|
mysql_close(it->conn);
|
|
|
|
|
it->conn = NULL;
|
2009-08-11 12:17:38 +00:00
|
|
|
}
|
|
|
|
|
}
|
2010-02-17 07:17:06 +00:00
|
|
|
m_connections.clear();
|
2009-08-11 12:17:38 +00:00
|
|
|
}
|