aboutsummaryrefslogtreecommitdiff
path: root/src/shared/Database
diff options
context:
space:
mode:
Diffstat (limited to 'src/shared/Database')
-rw-r--r--src/shared/Database/DBCFileLoader.cpp42
-rw-r--r--src/shared/Database/DBCFileLoader.h12
-rw-r--r--src/shared/Database/DBCStore.h24
-rw-r--r--src/shared/Database/Database.cpp42
-rw-r--r--src/shared/Database/Database.h22
-rw-r--r--src/shared/Database/DatabaseEnv.h6
-rw-r--r--src/shared/Database/DatabaseImpl.h27
-rw-r--r--src/shared/Database/DatabaseMysql.cpp70
-rw-r--r--src/shared/Database/DatabaseMysql.h14
-rw-r--r--src/shared/Database/Field.cpp10
-rw-r--r--src/shared/Database/Field.h10
-rw-r--r--src/shared/Database/MySQLDelayThread.h3
-rw-r--r--src/shared/Database/QueryResult.h15
-rw-r--r--src/shared/Database/QueryResultMysql.cpp15
-rw-r--r--src/shared/Database/QueryResultMysql.h8
-rw-r--r--src/shared/Database/SQLStorage.cpp8
-rw-r--r--src/shared/Database/SQLStorage.h19
-rw-r--r--src/shared/Database/SQLStorageImpl.h20
-rw-r--r--src/shared/Database/SqlDelayThread.cpp6
-rw-r--r--src/shared/Database/SqlDelayThread.h8
-rw-r--r--src/shared/Database/SqlOperations.cpp26
-rw-r--r--src/shared/Database/SqlOperations.h15
22 files changed, 422 insertions, 0 deletions
diff --git a/src/shared/Database/DBCFileLoader.cpp b/src/shared/Database/DBCFileLoader.cpp
index adf796fbce6..e7ebeedecfb 100644
--- a/src/shared/Database/DBCFileLoader.cpp
+++ b/src/shared/Database/DBCFileLoader.cpp
@@ -17,42 +17,59 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+
#include "DBCFileLoader.h"
+
DBCFileLoader::DBCFileLoader()
{
data = NULL;
fieldsOffset = NULL;
}
+
bool DBCFileLoader::Load(const char *filename, const char *fmt)
{
+
uint32 header;
if(data)
{
delete [] data;
data=NULL;
}
+
FILE * f=fopen(filename,"rb");
if(!f)return false;
+
if(fread(&header,4,1,f)!=1) // Number of records
return false;
+
EndianConvert(header);
if(header!=0x43424457)
return false; //'WDBC'
+
if(fread(&recordCount,4,1,f)!=1) // Number of records
return false;
+
EndianConvert(recordCount);
+
if(fread(&fieldCount,4,1,f)!=1) // Number of fields
return false;
+
EndianConvert(fieldCount);
+
if(fread(&recordSize,4,1,f)!=1) // Size of a record
return false;
+
EndianConvert(recordSize);
+
if(fread(&stringSize,4,1,f)!=1) // String size
return false;
+
EndianConvert(stringSize);
+
fieldsOffset = new uint32[fieldCount];
fieldsOffset[0] = 0;
for(uint32 i = 1; i < fieldCount; i++)
@@ -63,13 +80,17 @@ bool DBCFileLoader::Load(const char *filename, const char *fmt)
else // 4 byte fields (int32/float/strings)
fieldsOffset[i] += 4;
}
+
data = new unsigned char[recordSize*recordCount+stringSize];
stringTable = data + recordSize*recordCount;
+
if(fread(data,recordSize*recordCount+stringSize,1,f)!=1)
return false;
+
fclose(f);
return true;
}
+
DBCFileLoader::~DBCFileLoader()
{
if(data)
@@ -77,11 +98,13 @@ DBCFileLoader::~DBCFileLoader()
if(fieldsOffset)
delete [] fieldsOffset;
}
+
DBCFileLoader::Record DBCFileLoader::getRecord(size_t id)
{
assert(data);
return Record(*this, data + id*recordSize);
}
+
uint32 DBCFileLoader::GetFormatRecordSize(const char * format,int32* index_pos)
{
uint32 recordsize = 0;
@@ -107,10 +130,13 @@ uint32 DBCFileLoader::GetFormatRecordSize(const char * format,int32* index_pos)
recordsize += 1;
break;
}
+
if(index_pos)
*index_pos = i;
+
return recordsize;
}
+
char* DBCFileLoader::AutoProduceData(const char* format, uint32& records, char**& indexTable, uint32 sqlRecordCount, uint32 sqlHighestIndex, char *& sqlDataTable)
{
/*
@@ -120,14 +146,18 @@ char* DBCFileLoader::AutoProduceData(const char* format, uint32& records, char**
float field1,
int field2
}entry;
+
this func will generate entry[rows] data;
*/
+
typedef char * ptr;
if(strlen(format)!=fieldCount)
return NULL;
+
//get struct size and index pos
int32 i;
uint32 recordsize=GetFormatRecordSize(format,&i);
+
if(i>=0)
{
uint32 maxi=0;
@@ -137,9 +167,11 @@ char* DBCFileLoader::AutoProduceData(const char* format, uint32& records, char**
uint32 ind=getRecord(y).getUInt (i);
if(ind>maxi)maxi=ind;
}
+
// If higher index avalible from sql - use it instead of dbcs
if (sqlHighestIndex > maxi)
maxi = sqlHighestIndex;
+
++maxi;
records=maxi;
indexTable=new ptr[maxi];
@@ -150,8 +182,11 @@ char* DBCFileLoader::AutoProduceData(const char* format, uint32& records, char**
records = recordCount + sqlRecordCount;
indexTable = new ptr[recordCount+ sqlRecordCount];
}
+
char* dataTable= new char[(recordCount + sqlRecordCount)*recordsize];
+
uint32 offset=0;
+
for(uint32 y =0;y<recordCount;++y)
{
if(i>=0)
@@ -160,6 +195,7 @@ char* DBCFileLoader::AutoProduceData(const char* format, uint32& records, char**
}
else
indexTable[y]=&dataTable[offset];
+
for(uint32 x=0;x<fieldCount;x++)
{
switch(format[x])
@@ -185,15 +221,20 @@ char* DBCFileLoader::AutoProduceData(const char* format, uint32& records, char**
}
}
sqlDataTable = dataTable + offset;
+
return dataTable;
}
+
char* DBCFileLoader::AutoProduceStrings(const char* format, char* dataTable)
{
if(strlen(format)!=fieldCount)
return NULL;
+
char* stringPool= new char[stringSize];
memcpy(stringPool,stringTable,stringSize);
+
uint32 offset=0;
+
for(uint32 y =0;y<recordCount;y++)
{
for(uint32 x=0;x<fieldCount;x++)
@@ -219,6 +260,7 @@ char* DBCFileLoader::AutoProduceStrings(const char* format, char* dataTable)
break;
}
}
+
return stringPool;
}
diff --git a/src/shared/Database/DBCFileLoader.h b/src/shared/Database/DBCFileLoader.h
index fd1f5539ee3..ef29af84bc1 100644
--- a/src/shared/Database/DBCFileLoader.h
+++ b/src/shared/Database/DBCFileLoader.h
@@ -15,11 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+
#ifndef DBC_FILE_LOADER_H
#define DBC_FILE_LOADER_H
#include "Platform/Define.h"
#include "Utilities/ByteConverter.h"
#include <cassert>
+
enum
{
FT_NA='x', //not used or unknown, 4 byte size
@@ -34,12 +36,15 @@ enum
FT_SQL_PRESENT='p', //Used in sql format to mark column present in sql dbc
FT_SQL_ABSENT='a' //Used in sql format to mark column absent in sql dbc
};
+
class DBCFileLoader
{
public:
DBCFileLoader();
~DBCFileLoader();
+
bool Load(const char *filename, const char *fmt);
+
class Record
{
public:
@@ -62,6 +67,7 @@ class DBCFileLoader
assert(field < file.fieldCount);
return *reinterpret_cast<uint8*>(offset+file.GetOffset(field));
}
+
const char *getString(size_t field) const
{
assert(field < file.fieldCount);
@@ -69,15 +75,20 @@ class DBCFileLoader
assert(stringOffset < file.stringSize);
return reinterpret_cast<char*>(file.stringTable + stringOffset);
}
+
private:
Record(DBCFileLoader &file_, unsigned char *offset_): offset(offset_), file(file_) {}
unsigned char *offset;
DBCFileLoader &file;
+
friend class DBCFileLoader;
+
};
+
// Get record by id
Record getRecord(size_t id);
/// Get begin iterator over records
+
uint32 GetNumRows() const { return recordCount;}
uint32 GetRowSize() const { return recordSize;}
uint32 GetCols() const { return fieldCount; }
@@ -87,6 +98,7 @@ class DBCFileLoader
char* AutoProduceStrings(const char* fmt, char* dataTable);
static uint32 GetFormatRecordSize(const char * format, int32 * index_pos = NULL);
private:
+
uint32 recordSize;
uint32 recordCount;
uint32 fieldCount;
diff --git a/src/shared/Database/DBCStore.h b/src/shared/Database/DBCStore.h
index 60e533a88e1..e02265ec523 100644
--- a/src/shared/Database/DBCStore.h
+++ b/src/shared/Database/DBCStore.h
@@ -15,10 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+
#ifndef DBCSTORE_H
#define DBCSTORE_H
+
#include "DBCFileLoader.h"
#include "Log.h"
+
struct SqlDbc
{
const std::string * formatString;
@@ -38,6 +41,7 @@ struct SqlDbc
else if (sqlTableName[i] == '.')
sqlTableName[i] = '_';
}
+
// Get sql index position
DBCFileLoader::GetFormatRecordSize(fmt, &indexPos);
if (indexPos>=0)
@@ -55,6 +59,7 @@ struct SqlDbc
}
}
};
+
template<class T>
class DBCStorage
{
@@ -62,16 +67,19 @@ class DBCStorage
public:
explicit DBCStorage(const char *f) : nCount(0), fieldCount(0), fmt(f), indexTable(NULL), m_dataTable(NULL) { }
~DBCStorage() { Clear(); }
+
T const* LookupEntry(uint32 id) const { return (id>=nCount)?NULL:indexTable[id]; }
uint32 GetNumRows() const { return nCount; }
char const* GetFormat() const { return fmt; }
uint32 GetFieldCount() const { return fieldCount; }
+
bool Load(char const* fn, SqlDbc * sql)
{
DBCFileLoader dbc;
// Check if load was sucessful, only then continue
if(!dbc.Load(fn, fmt))
return false;
+
uint32 sqlRecordCount = 0;
uint32 sqlHighestIndex = 0;
Field *fields = NULL;
@@ -83,6 +91,7 @@ class DBCStorage
if (sql->indexPos >= 0)
query +=" ORDER BY + " + *sql->indexName + " DESC";
query += ";";
+
result = WorldDatabase.Query(query.c_str());
if (result)
{
@@ -103,7 +112,9 @@ class DBCStorage
char * sqlDataTable;
fieldCount = dbc.GetCols();
m_dataTable = (T*)dbc.AutoProduceData(fmt,nCount,(char**&)indexTable, sqlRecordCount, sqlHighestIndex, sqlDataTable);
+
m_stringPoolList.push_back(dbc.AutoProduceStrings(fmt,(char*)m_dataTable));
+
// Insert sql data into arrays
if (result)
{
@@ -115,6 +126,7 @@ class DBCStorage
{
if (!fields)
fields = result->Fetch();
+
if(sql->indexPos >= 0)
{
uint32 id = fields[sql->sqlIndexPos].GetUInt32();
@@ -129,6 +141,7 @@ class DBCStorage
indexTable[rowIndex]=(T*)&sqlDataTable[offset];
uint32 columnNumber = 0;
uint32 sqlColumnNumber = 0;
+
for(;columnNumber < sql->formatString->size();++columnNumber)
{
if ((*sql->formatString)[columnNumber] == FT_SQL_ABSENT)
@@ -198,35 +211,44 @@ class DBCStorage
delete result;
return false;
}
+
fields = NULL;
++rowIndex;
}while (result->NextRow());
}
delete result;
}
+
// error in dbc file at loading if NULL
return indexTable!=NULL;
}
+
bool LoadStringsFrom(char const* fn)
{
// DBC must be already loaded using Load
if(!indexTable)
return false;
+
DBCFileLoader dbc;
// Check if load was successful, only then continue
if(!dbc.Load(fn, fmt))
return false;
+
m_stringPoolList.push_back(dbc.AutoProduceStrings(fmt,(char*)m_dataTable));
+
return true;
}
+
void Clear()
{
if (!indexTable)
return;
+
delete[] ((char*)indexTable);
indexTable = NULL;
delete[] ((char*)m_dataTable);
m_dataTable = NULL;
+
while(!m_stringPoolList.empty())
{
delete[] m_stringPoolList.front();
@@ -234,6 +256,7 @@ class DBCStorage
}
nCount = 0;
}
+
private:
char const* fmt;
uint32 nCount;
@@ -242,4 +265,5 @@ class DBCStorage
T* m_dataTable;
StringPoolList m_stringPoolList;
};
+
#endif
diff --git a/src/shared/Database/Database.cpp b/src/shared/Database/Database.cpp
index 9bfae3479bf..572d3db6f1d 100644
--- a/src/shared/Database/Database.cpp
+++ b/src/shared/Database/Database.cpp
@@ -17,17 +17,22 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+
#include "DatabaseEnv.h"
#include "Config/ConfigEnv.h"
+
#include "Common.h"
#include "../../game/UpdateFields.h"
+
#include <ctime>
#include <iostream>
#include <fstream>
+
Database::~Database()
{
/*Delete objects*/
}
+
bool Database::Initialize(const char *)
{
// Enable logging of SQL commands (usally only GM commands)
@@ -39,37 +44,46 @@ bool Database::Initialize(const char *)
if((m_logsDir.at(m_logsDir.length()-1)!='/') && (m_logsDir.at(m_logsDir.length()-1)!='\\'))
m_logsDir.append("/");
}
+
return true;
}
+
void Database::ThreadStart()
{
}
+
void Database::ThreadEnd()
{
}
+
void Database::escape_string(std::string& str)
{
if(str.empty())
return;
+
char* buf = new char[str.size()*2+1];
escape_string(buf,str.c_str(),str.size());
str = buf;
delete[] buf;
}
+
bool Database::PExecuteLog(const char * format,...)
{
if (!format)
return false;
+
va_list ap;
char szQuery [MAX_QUERY_LEN];
va_start(ap, format);
int res = vsnprintf( szQuery, MAX_QUERY_LEN, format, ap );
va_end(ap);
+
if(res==-1)
{
sLog.outError("SQL Query truncated (and not execute) for format: %s",format);
return false;
}
+
if( m_logSQL )
{
time_t curr;
@@ -78,6 +92,7 @@ bool Database::PExecuteLog(const char * format,...)
local=*(localtime(&curr)); // dereference and assign
char fName[128];
sprintf( fName, "%04d-%02d-%02d_logSQL.sql", local.tm_year+1900, local.tm_mon+1, local.tm_mday );
+
FILE* log_file;
std::string logsDir_fname = m_logsDir+fName;
log_file = fopen(logsDir_fname.c_str(), "a");
@@ -92,58 +107,74 @@ bool Database::PExecuteLog(const char * format,...)
sLog.outError("SQL-Logging is disabled - Log file for the SQL commands could not be openend: %s",fName);
}
}
+
return Execute(szQuery);
}
+
void Database::SetResultQueue(SqlResultQueue * queue)
{
m_queryQueues[ACE_Based::Thread::current()] = queue;
+
}
+
QueryResult* Database::PQuery(const char *format,...)
{
if(!format) return NULL;
+
va_list ap;
char szQuery [MAX_QUERY_LEN];
va_start(ap, format);
int res = vsnprintf( szQuery, MAX_QUERY_LEN, format, ap );
va_end(ap);
+
if(res==-1)
{
sLog.outError("SQL Query truncated (and not execute) for format: %s",format);
return false;
}
+
return Query(szQuery);
}
+
QueryNamedResult* Database::PQueryNamed(const char *format,...)
{
if(!format) return NULL;
+
va_list ap;
char szQuery [MAX_QUERY_LEN];
va_start(ap, format);
int res = vsnprintf( szQuery, MAX_QUERY_LEN, format, ap );
va_end(ap);
+
if(res==-1)
{
sLog.outError("SQL Query truncated (and not execute) for format: %s",format);
return false;
}
+
return QueryNamed(szQuery);
}
+
bool Database::PExecute(const char * format,...)
{
if (!format)
return false;
+
va_list ap;
char szQuery [MAX_QUERY_LEN];
va_start(ap, format);
int res = vsnprintf( szQuery, MAX_QUERY_LEN, format, ap );
va_end(ap);
+
if(res==-1)
{
sLog.outError("SQL Query truncated (and not execute) for format: %s",format);
return false;
}
+
return Execute(szQuery);
}
+
bool Database::_UpdateDataBlobValue(const uint32 guid, const uint32 field, const int32 value)
{
return PExecute(
@@ -153,6 +184,7 @@ bool Database::_UpdateDataBlobValue(const uint32 guid, const uint32 field, const
"' ',SUBSTRING_INDEX(`data`,' ',%i)) WHERE guid=%u",
field, field+1, value, -int32(PLAYER_END-field), guid);
}
+
bool Database::_SetDataBlobValue(const uint32 guid, const uint32 field, const uint32 value)
{
return PExecute(
@@ -161,22 +193,27 @@ bool Database::_SetDataBlobValue(const uint32 guid, const uint32 field, const ui
"%u,' ',SUBSTRING_INDEX(`data`,' ',%i)) WHERE guid=%u",
field, value, -int32(PLAYER_END-field), guid);
}
+
bool Database::DirectPExecute(const char * format,...)
{
if (!format)
return false;
+
va_list ap;
char szQuery [MAX_QUERY_LEN];
va_start(ap, format);
int res = vsnprintf( szQuery, MAX_QUERY_LEN, format, ap );
va_end(ap);
+
if(res==-1)
{
sLog.outError("SQL Query truncated (and not execute) for format: %s",format);
return false;
}
+
return DirectExecute(szQuery);
}
+
bool Database::CheckRequiredField( char const* table_name, char const* required_name )
{
// check required field
@@ -186,7 +223,9 @@ bool Database::CheckRequiredField( char const* table_name, char const* required_
delete result;
return true;
}
+
// check fail, prepare readabale error message
+
// search current required_* field in DB
QueryNamedResult* result2 = PQueryNamed("SELECT * FROM %s LIMIT 1",table_name);
if(result2)
@@ -201,7 +240,9 @@ bool Database::CheckRequiredField( char const* table_name, char const* required_
break;
}
}
+
delete result2;
+
if(!reqName.empty())
sLog.outErrorDb("Table `%s` have field `%s` but expected `%s`! Not all sql updates applied?",table_name,reqName.c_str(),required_name);
else
@@ -209,5 +250,6 @@ bool Database::CheckRequiredField( char const* table_name, char const* required_
}
else
sLog.outErrorDb("Table `%s` fields list query fail but expected have `%s`! No records in `%s`?",table_name,required_name,table_name);
+
return false;
}
diff --git a/src/shared/Database/Database.h b/src/shared/Database/Database.h
index 34438d994dc..6172a61c5f9 100644
--- a/src/shared/Database/Database.h
+++ b/src/shared/Database/Database.h
@@ -17,35 +17,48 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+
#ifndef DATABASE_H
#define DATABASE_H
+
#include "Threading.h"
#include "Utilities/UnorderedMap.h"
#include "Database/SqlDelayThread.h"
+
class SqlTransaction;
class SqlResultQueue;
class SqlQueryHolder;
+
typedef UNORDERED_MAP<ACE_Based::Thread* , SqlTransaction*> TransactionQueues;
typedef UNORDERED_MAP<ACE_Based::Thread* , SqlResultQueue*> QueryQueues;
+
#define MAX_QUERY_LEN 32*1024
+
class TRINITY_DLL_SPEC Database
{
protected:
Database() : m_threadBody(NULL), m_delayThread(NULL) {};
+
TransactionQueues m_tranQueues; ///< Transaction queues from diff. threads
QueryQueues m_queryQueues; ///< Query queues from diff threads
SqlDelayThread* m_threadBody; ///< Pointer to delay sql executer (owned by m_delayThread)
ACE_Based::Thread* m_delayThread; ///< Pointer to executer thread
+
public:
+
virtual ~Database();
+
virtual bool Initialize(const char *infoString);
virtual void InitDelayThread() = 0;
virtual void HaltDelayThread() = 0;
+
virtual QueryResult* Query(const char *sql) = 0;
QueryResult* PQuery(const char *format,...) ATTR_PRINTF(2,3);
virtual QueryNamedResult* QueryNamed(const char *sql) = 0;
QueryNamedResult* PQueryNamed(const char *format,...) ATTR_PRINTF(2,3);
+
/// Async queries and query holders, implemented in DatabaseImpl.h
+
// Query / member
template<class Class>
bool AsyncQuery(Class *object, void (Class::*method)(QueryResult*), const char *sql);
@@ -83,14 +96,18 @@ class TRINITY_DLL_SPEC Database
bool DelayQueryHolder(Class *object, void (Class::*method)(QueryResult*, SqlQueryHolder*), SqlQueryHolder *holder);
template<class Class, typename ParamType1>
bool DelayQueryHolder(Class *object, void (Class::*method)(QueryResult*, SqlQueryHolder*, ParamType1), SqlQueryHolder *holder, ParamType1 param1);
+
virtual bool Execute(const char *sql) = 0;
bool PExecute(const char *format,...) ATTR_PRINTF(2,3);
virtual bool DirectExecute(const char* sql) = 0;
bool DirectPExecute(const char *format,...) ATTR_PRINTF(2,3);
+
bool _UpdateDataBlobValue(const uint32 guid, const uint32 field, const int32 value);
bool _SetDataBlobValue(const uint32 guid, const uint32 field, const uint32 value);
+
// Writes SQL commands to a LOG file (see Trinityd.conf "LogSQL")
bool PExecuteLog(const char *format,...) ATTR_PRINTF(2,3);
+
virtual bool BeginTransaction() // nothing do if DB not support transactions
{
return true;
@@ -103,15 +120,20 @@ class TRINITY_DLL_SPEC Database
{
return false;
}
+
virtual operator bool () const = 0;
+
virtual unsigned long escape_string(char *to, const char *from, unsigned long length) { strncpy(to,from,length); return length; }
void escape_string(std::string& str);
+
// must be called before first query in thread (one time for thread using one from existed Database objects)
virtual void ThreadStart();
// must be called before finish thread run (one time for thread using one from existed Database objects)
virtual void ThreadEnd();
+
// sets the result queue of the current thread, be careful what thread you call this from
void SetResultQueue(SqlResultQueue * queue);
+
bool CheckRequiredField(char const* table_name, char const* required_name);
private:
bool m_logSQL;
diff --git a/src/shared/Database/DatabaseEnv.h b/src/shared/Database/DatabaseEnv.h
index 2e89d74e97c..d5d6867e82f 100644
--- a/src/shared/Database/DatabaseEnv.h
+++ b/src/shared/Database/DatabaseEnv.h
@@ -17,13 +17,17 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+
#if !defined(DATABASEENV_H)
#define DATABASEENV_H
+
#include "Common.h"
#include "Log.h"
#include "Errors.h"
+
#include "Database/Field.h"
#include "Database/QueryResult.h"
+
#ifdef DO_POSTGRESQL
#include "Database/QueryResultPostgre.h"
#include "Database/Database.h"
@@ -43,8 +47,10 @@ typedef DatabaseMysql DatabaseType;
#define _CONCAT3_(A,B,C) "CONCAT( " A " , " B " , " C " )"
#define _OFFSET_ "LIMIT %d,1"
#endif
+
extern DatabaseType WorldDatabase;
extern DatabaseType CharacterDatabase;
extern DatabaseType loginDatabase;
+
#endif
diff --git a/src/shared/Database/DatabaseImpl.h b/src/shared/Database/DatabaseImpl.h
index ac856664290..7cbd0ed8ba5 100644
--- a/src/shared/Database/DatabaseImpl.h
+++ b/src/shared/Database/DatabaseImpl.h
@@ -17,9 +17,12 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+
#include "Database/Database.h"
#include "Database/SqlOperations.h"
+
/// Function body definitions for the template function members of the Database class
+
#define ASYNC_QUERY_BODY(sql, queue_itr) \
if (!sql) return false; \
\
@@ -30,6 +33,7 @@
queue_itr = m_queryQueues.find(queryThread); \
if (queue_itr == m_queryQueues.end()) return false; \
}
+
#define ASYNC_PQUERY_BODY(format, szQuery) \
if(!format) return false; \
\
@@ -48,6 +52,7 @@
return false; \
} \
}
+
#define ASYNC_DELAYHOLDER_BODY(holder, queue_itr) \
if (!holder) return false; \
\
@@ -58,7 +63,9 @@
queue_itr = m_queryQueues.find(queryThread); \
if (queue_itr == m_queryQueues.end()) return false; \
}
+
// -- Query / member --
+
template<class Class>
bool
Database::AsyncQuery(Class *object, void (Class::*method)(QueryResult*), const char *sql)
@@ -66,6 +73,7 @@ Database::AsyncQuery(Class *object, void (Class::*method)(QueryResult*), const c
ASYNC_QUERY_BODY(sql, itr)
return m_threadBody->Delay(new SqlQuery(sql, new Trinity::QueryCallback<Class>(object, method), itr->second));
}
+
template<class Class, typename ParamType1>
bool
Database::AsyncQuery(Class *object, void (Class::*method)(QueryResult*, ParamType1), ParamType1 param1, const char *sql)
@@ -73,6 +81,7 @@ Database::AsyncQuery(Class *object, void (Class::*method)(QueryResult*, ParamTyp
ASYNC_QUERY_BODY(sql, itr)
return m_threadBody->Delay(new SqlQuery(sql, new Trinity::QueryCallback<Class, ParamType1>(object, method, (QueryResult*)NULL, param1), itr->second));
}
+
template<class Class, typename ParamType1, typename ParamType2>
bool
Database::AsyncQuery(Class *object, void (Class::*method)(QueryResult*, ParamType1, ParamType2), ParamType1 param1, ParamType2 param2, const char *sql)
@@ -80,6 +89,7 @@ Database::AsyncQuery(Class *object, void (Class::*method)(QueryResult*, ParamTyp
ASYNC_QUERY_BODY(sql, itr)
return m_threadBody->Delay(new SqlQuery(sql, new Trinity::QueryCallback<Class, ParamType1, ParamType2>(object, method, (QueryResult*)NULL, param1, param2), itr->second));
}
+
template<class Class, typename ParamType1, typename ParamType2, typename ParamType3>
bool
Database::AsyncQuery(Class *object, void (Class::*method)(QueryResult*, ParamType1, ParamType2, ParamType3), ParamType1 param1, ParamType2 param2, ParamType3 param3, const char *sql)
@@ -87,7 +97,9 @@ Database::AsyncQuery(Class *object, void (Class::*method)(QueryResult*, ParamTyp
ASYNC_QUERY_BODY(sql, itr)
return m_threadBody->Delay(new SqlQuery(sql, new Trinity::QueryCallback<Class, ParamType1, ParamType2, ParamType3>(object, method, (QueryResult*)NULL, param1, param2, param3), itr->second));
}
+
// -- Query / static --
+
template<typename ParamType1>
bool
Database::AsyncQuery(void (*method)(QueryResult*, ParamType1), ParamType1 param1, const char *sql)
@@ -95,6 +107,7 @@ Database::AsyncQuery(void (*method)(QueryResult*, ParamType1), ParamType1 param1
ASYNC_QUERY_BODY(sql, itr)
return m_threadBody->Delay(new SqlQuery(sql, new Trinity::SQueryCallback<ParamType1>(method, (QueryResult*)NULL, param1), itr->second));
}
+
template<typename ParamType1, typename ParamType2>
bool
Database::AsyncQuery(void (*method)(QueryResult*, ParamType1, ParamType2), ParamType1 param1, ParamType2 param2, const char *sql)
@@ -102,6 +115,7 @@ Database::AsyncQuery(void (*method)(QueryResult*, ParamType1, ParamType2), Param
ASYNC_QUERY_BODY(sql, itr)
return m_threadBody->Delay(new SqlQuery(sql, new Trinity::SQueryCallback<ParamType1, ParamType2>(method, (QueryResult*)NULL, param1, param2), itr->second));
}
+
template<typename ParamType1, typename ParamType2, typename ParamType3>
bool
Database::AsyncQuery(void (*method)(QueryResult*, ParamType1, ParamType2, ParamType3), ParamType1 param1, ParamType2 param2, ParamType3 param3, const char *sql)
@@ -109,7 +123,9 @@ Database::AsyncQuery(void (*method)(QueryResult*, ParamType1, ParamType2, ParamT
ASYNC_QUERY_BODY(sql, itr)
return m_threadBody->Delay(new SqlQuery(sql, new Trinity::SQueryCallback<ParamType1, ParamType2, ParamType3>(method, (QueryResult*)NULL, param1, param2, param3), itr->second));
}
+
// -- PQuery / member --
+
template<class Class>
bool
Database::AsyncPQuery(Class *object, void (Class::*method)(QueryResult*), const char *format,...)
@@ -117,6 +133,7 @@ Database::AsyncPQuery(Class *object, void (Class::*method)(QueryResult*), const
ASYNC_PQUERY_BODY(format, szQuery)
return AsyncQuery(object, method, szQuery);
}
+
template<class Class, typename ParamType1>
bool
Database::AsyncPQuery(Class *object, void (Class::*method)(QueryResult*, ParamType1), ParamType1 param1, const char *format,...)
@@ -124,6 +141,7 @@ Database::AsyncPQuery(Class *object, void (Class::*method)(QueryResult*, ParamTy
ASYNC_PQUERY_BODY(format, szQuery)
return AsyncQuery(object, method, param1, szQuery);
}
+
template<class Class, typename ParamType1, typename ParamType2>
bool
Database::AsyncPQuery(Class *object, void (Class::*method)(QueryResult*, ParamType1, ParamType2), ParamType1 param1, ParamType2 param2, const char *format,...)
@@ -131,6 +149,7 @@ Database::AsyncPQuery(Class *object, void (Class::*method)(QueryResult*, ParamTy
ASYNC_PQUERY_BODY(format, szQuery)
return AsyncQuery(object, method, param1, param2, szQuery);
}
+
template<class Class, typename ParamType1, typename ParamType2, typename ParamType3>
bool
Database::AsyncPQuery(Class *object, void (Class::*method)(QueryResult*, ParamType1, ParamType2, ParamType3), ParamType1 param1, ParamType2 param2, ParamType3 param3, const char *format,...)
@@ -138,7 +157,9 @@ Database::AsyncPQuery(Class *object, void (Class::*method)(QueryResult*, ParamTy
ASYNC_PQUERY_BODY(format, szQuery)
return AsyncQuery(object, method, param1, param2, param3, szQuery);
}
+
// -- PQuery / static --
+
template<typename ParamType1>
bool
Database::AsyncPQuery(void (*method)(QueryResult*, ParamType1), ParamType1 param1, const char *format,...)
@@ -146,6 +167,7 @@ Database::AsyncPQuery(void (*method)(QueryResult*, ParamType1), ParamType1 param
ASYNC_PQUERY_BODY(format, szQuery)
return AsyncQuery(method, param1, szQuery);
}
+
template<typename ParamType1, typename ParamType2>
bool
Database::AsyncPQuery(void (*method)(QueryResult*, ParamType1, ParamType2), ParamType1 param1, ParamType2 param2, const char *format,...)
@@ -153,6 +175,7 @@ Database::AsyncPQuery(void (*method)(QueryResult*, ParamType1, ParamType2), Para
ASYNC_PQUERY_BODY(format, szQuery)
return AsyncQuery(method, param1, param2, szQuery);
}
+
template<typename ParamType1, typename ParamType2, typename ParamType3>
bool
Database::AsyncPQuery(void (*method)(QueryResult*, ParamType1, ParamType2, ParamType3), ParamType1 param1, ParamType2 param2, ParamType3 param3, const char *format,...)
@@ -160,7 +183,9 @@ Database::AsyncPQuery(void (*method)(QueryResult*, ParamType1, ParamType2, Param
ASYNC_PQUERY_BODY(format, szQuery)
return AsyncQuery(method, param1, param2, param3, szQuery);
}
+
// -- QueryHolder --
+
template<class Class>
bool
Database::DelayQueryHolder(Class *object, void (Class::*method)(QueryResult*, SqlQueryHolder*), SqlQueryHolder *holder)
@@ -168,6 +193,7 @@ Database::DelayQueryHolder(Class *object, void (Class::*method)(QueryResult*, Sq
ASYNC_DELAYHOLDER_BODY(holder, itr)
return holder->Execute(new Trinity::QueryCallback<Class, SqlQueryHolder*>(object, method, (QueryResult*)NULL, holder), m_threadBody, itr->second);
}
+
template<class Class, typename ParamType1>
bool
Database::DelayQueryHolder(Class *object, void (Class::*method)(QueryResult*, SqlQueryHolder*, ParamType1), SqlQueryHolder *holder, ParamType1 param1)
@@ -175,6 +201,7 @@ Database::DelayQueryHolder(Class *object, void (Class::*method)(QueryResult*, Sq
ASYNC_DELAYHOLDER_BODY(holder, itr)
return holder->Execute(new Trinity::QueryCallback<Class, SqlQueryHolder*, ParamType1>(object, method, (QueryResult*)NULL, holder, param1), m_threadBody, itr->second);
}
+
#undef ASYNC_QUERY_BODY
#undef ASYNC_PQUERY_BODY
#undef ASYNC_DELAYHOLDER_BODY
diff --git a/src/shared/Database/DatabaseMysql.cpp b/src/shared/Database/DatabaseMysql.cpp
index 235fb96f127..f08ea67cbbe 100644
--- a/src/shared/Database/DatabaseMysql.cpp
+++ b/src/shared/Database/DatabaseMysql.cpp
@@ -17,7 +17,9 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+
#ifndef DO_POSTGRESQL
+
#include "Util.h"
#include "Policies/SingletonImp.h"
#include "Platform/Define.h"
@@ -26,15 +28,19 @@
#include "Database/MySQLDelayThread.h"
#include "Database/SqlOperations.h"
#include "Timer.h"
+
void DatabaseMysql::ThreadStart()
{
mysql_thread_init();
}
+
void DatabaseMysql::ThreadEnd()
{
mysql_thread_end();
}
+
size_t DatabaseMysql::db_count = 0;
+
DatabaseMysql::DatabaseMysql() : Database(), mMysql(0)
{
// before first connection
@@ -42,6 +48,7 @@ DatabaseMysql::DatabaseMysql() : Database(), mMysql(0)
{
// Mysql Library Init
mysql_library_init(-1, NULL, NULL);
+
if (!mysql_thread_safe())
{
sLog.outError("FATAL ERROR: Used MySQL library isn't thread-safe.");
@@ -49,20 +56,26 @@ DatabaseMysql::DatabaseMysql() : Database(), mMysql(0)
}
}
}
+
DatabaseMysql::~DatabaseMysql()
{
if (m_delayThread)
HaltDelayThread();
+
if (mMysql)
mysql_close(mMysql);
+
//Free Mysql library pointers for last ~DB
if(--db_count == 0)
mysql_library_end();
}
+
bool DatabaseMysql::Initialize(const char *infoString)
{
+
if(!Database::Initialize(infoString))
return false;
+
tranThread = NULL;
MYSQL *mysqlInit;
mysqlInit = mysql_init(NULL);
@@ -71,13 +84,19 @@ bool DatabaseMysql::Initialize(const char *infoString)
sLog.outError( "Could not initialize Mysql connection" );
return false;
}
+
InitDelayThread();
+
Tokens tokens = StrSplit(infoString, ";");
+
Tokens::iterator iter;
+
std::string host, port_or_socket, user, password, database;
int port;
char const* unix_socket;
+
iter = tokens.begin();
+
if(iter != tokens.end())
host = *iter++;
if(iter != tokens.end())
@@ -88,6 +107,7 @@ bool DatabaseMysql::Initialize(const char *infoString)
password = *iter++;
if(iter != tokens.end())
database = *iter++;
+
mysql_options(mysqlInit,MYSQL_SET_CHARSET_NAME,"utf8");
#ifdef WIN32
if(host==".") // named pipe use option (Windows)
@@ -117,14 +137,17 @@ bool DatabaseMysql::Initialize(const char *infoString)
unix_socket = 0;
}
#endif
+
mMysql = mysql_real_connect(mysqlInit, host.c_str(), user.c_str(),
password.c_str(), database.c_str(), port, unix_socket, 0);
+
if (mMysql)
{
sLog.outDetail( "Connected to MySQL database at %s",
host.c_str());
sLog.outString( "MySQL client library: %s", mysql_get_client_info());
sLog.outString( "MySQL server ver: %s ", mysql_get_server_info( mMysql));
+
/*----------SET AUTOCOMMIT ON---------*/
// It seems mysql 5.0.x have enabled this feature
// by default. In crash case you can lose data!!!
@@ -138,10 +161,12 @@ bool DatabaseMysql::Initialize(const char *infoString)
else
sLog.outDetail("AUTOCOMMIT NOT SET TO 1");
/*-------------------------------------*/
+
// set connection properties to UTF8 to properly handle locales for different
// server configs - core sends data in UTF8, so MySQL must expect UTF8 too
PExecute("SET NAMES `utf8`");
PExecute("SET CHARACTER SET `utf8`");
+
#if MYSQL_VERSION_ID >= 50003
my_bool my_true = (my_bool)1;
if (mysql_options(mMysql, MYSQL_OPT_RECONNECT, &my_true))
@@ -155,6 +180,7 @@ bool DatabaseMysql::Initialize(const char *infoString)
#else
#warning "Your mySQL client lib version does not support reconnecting after a timeout.\nIf this causes you any trouble we advice you to upgrade your mySQL client libs to at least mySQL 5.0.13 to resolve this problem."
#endif
+
return true;
}
else
@@ -165,10 +191,12 @@ bool DatabaseMysql::Initialize(const char *infoString)
return false;
}
}
+
bool DatabaseMysql::_Query(const char *sql, MYSQL_RES **pResult, MYSQL_FIELD **pFields, uint64* pRowCount, uint32* pFieldCount)
{
if (!mMysql)
return 0;
+
{
// guarded block for thread-safe mySQL request
ACE_Guard<ACE_Thread_Mutex> query_connection_guard(mMutex);
@@ -187,54 +215,72 @@ bool DatabaseMysql::_Query(const char *sql, MYSQL_RES **pResult, MYSQL_FIELD **p
sLog.outDebug("[%u ms] SQL: %s", getMSTimeDiff(_s,getMSTime()), sql );
#endif
}
+
*pResult = mysql_store_result(mMysql);
*pRowCount = mysql_affected_rows(mMysql);
*pFieldCount = mysql_field_count(mMysql);
// end guarded block
}
+
if (!*pResult )
return false;
+
if (!*pRowCount)
{
mysql_free_result(*pResult);
return false;
}
+
*pFields = mysql_fetch_fields(*pResult);
return true;
}
+
QueryResult* DatabaseMysql::Query(const char *sql)
{
MYSQL_RES *result = NULL;
MYSQL_FIELD *fields = NULL;
uint64 rowCount = 0;
uint32 fieldCount = 0;
+
if(!_Query(sql,&result,&fields,&rowCount,&fieldCount))
return NULL;
+
QueryResultMysql *queryResult = new QueryResultMysql(result, fields, rowCount, fieldCount);
+
queryResult->NextRow();
+
return queryResult;
}
+
QueryNamedResult* DatabaseMysql::QueryNamed(const char *sql)
{
MYSQL_RES *result = NULL;
MYSQL_FIELD *fields = NULL;
uint64 rowCount = 0;
uint32 fieldCount = 0;
+
if(!_Query(sql,&result,&fields,&rowCount,&fieldCount))
return NULL;
+
QueryFieldNames names(fieldCount);
for (uint32 i = 0; i < fieldCount; i++)
names[i] = fields[i].name;
+
QueryResultMysql *queryResult = new QueryResultMysql(result, fields, rowCount, fieldCount);
+
queryResult->NextRow();
+
return new QueryNamedResult(queryResult,names);
}
+
bool DatabaseMysql::Execute(const char *sql)
{
if (!mMysql)
return false;
+
// don't use queued execution if it has not been initialized
if (!m_threadBody) return DirectExecute(sql);
+
tranThread = ACE_Based::Thread::current(); // owner of this transaction
TransactionQueues::iterator i = m_tranQueues.find(tranThread);
if (i != m_tranQueues.end() && i->second != NULL)
@@ -246,15 +292,19 @@ bool DatabaseMysql::Execute(const char *sql)
// Simple sql statement
m_threadBody->Delay(new SqlStatement(sql));
}
+
return true;
}
+
bool DatabaseMysql::DirectExecute(const char* sql)
{
if (!mMysql)
return false;
+
{
// guarded block for thread-safe mySQL request
ACE_Guard<ACE_Thread_Mutex> query_connection_guard(mMutex);
+
#ifdef MANGOS_DEBUG
uint32 _s = getMSTime();
#endif
@@ -272,8 +322,10 @@ bool DatabaseMysql::DirectExecute(const char* sql)
}
// end guarded block
}
+
return true;
}
+
bool DatabaseMysql::_TransactionCmd(const char *sql)
{
if (mysql_query(mMysql, sql))
@@ -288,15 +340,18 @@ bool DatabaseMysql::_TransactionCmd(const char *sql)
}
return true;
}
+
bool DatabaseMysql::BeginTransaction()
{
if (!mMysql)
return false;
+
// don't use queued execution if it has not been initialized
if (!m_threadBody)
{
if (tranThread == ACE_Based::Thread::current())
return false; // huh? this thread already started transaction
+
mMutex.acquire();
if (!_TransactionCmd("START TRANSACTION"))
{
@@ -305,19 +360,24 @@ bool DatabaseMysql::BeginTransaction()
}
return true; // transaction started
}
+
tranThread = ACE_Based::Thread::current(); // owner of this transaction
TransactionQueues::iterator i = m_tranQueues.find(tranThread);
if (i != m_tranQueues.end() && i->second != NULL)
// If for thread exists queue and also contains transaction
// delete that transaction (not allow trans in trans)
delete i->second;
+
m_tranQueues[tranThread] = new SqlTransaction();
+
return true;
}
+
bool DatabaseMysql::CommitTransaction()
{
if (!mMysql)
return false;
+
// don't use queued execution if it has not been initialized
if (!m_threadBody)
{
@@ -328,6 +388,7 @@ bool DatabaseMysql::CommitTransaction()
mMutex.release();
return _res;
}
+
tranThread = ACE_Based::Thread::current();
TransactionQueues::iterator i = m_tranQueues.find(tranThread);
if (i != m_tranQueues.end() && i->second != NULL)
@@ -339,10 +400,12 @@ bool DatabaseMysql::CommitTransaction()
else
return false;
}
+
bool DatabaseMysql::RollbackTransaction()
{
if (!mMysql)
return false;
+
// don't use queued execution if it has not been initialized
if (!m_threadBody)
{
@@ -353,6 +416,7 @@ bool DatabaseMysql::RollbackTransaction()
mMutex.release();
return _res;
}
+
tranThread = ACE_Based::Thread::current();
TransactionQueues::iterator i = m_tranQueues.find(tranThread);
if (i != m_tranQueues.end() && i->second != NULL)
@@ -362,22 +426,28 @@ bool DatabaseMysql::RollbackTransaction()
}
return true;
}
+
unsigned long DatabaseMysql::escape_string(char *to, const char *from, unsigned long length)
{
if (!mMysql || !to || !from || !length)
return 0;
+
return(mysql_real_escape_string(mMysql, to, from, length));
}
+
void DatabaseMysql::InitDelayThread()
{
assert(!m_delayThread);
+
//New delay thread for delay execute
m_threadBody = new MySQLDelayThread(this); // will deleted at m_delayThread delete
m_delayThread = new ACE_Based::Thread(m_threadBody);
}
+
void DatabaseMysql::HaltDelayThread()
{
if (!m_threadBody || !m_delayThread) return;
+
m_threadBody->Stop(); //Stop event
m_delayThread->wait(); //Wait for flush to DB
delete m_delayThread; //This also deletes m_threadBody
diff --git a/src/shared/Database/DatabaseMysql.h b/src/shared/Database/DatabaseMysql.h
index 3a7fa4f5def..4612ebfc462 100644
--- a/src/shared/Database/DatabaseMysql.h
+++ b/src/shared/Database/DatabaseMysql.h
@@ -17,13 +17,17 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+
#ifndef DO_POSTGRESQL
+
#ifndef _DATABASEMYSQL_H
#define _DATABASEMYSQL_H
+
#include "Database.h"
#include "Policies/Singleton.h"
#include "ace/Thread_Mutex.h"
#include "ace/Guard_T.h"
+
#ifdef WIN32
#define FD_SETSIZE 1024
#include <winsock2.h>
@@ -31,12 +35,15 @@
#else
#include <mysql.h>
#endif
+
class TRINITY_DLL_SPEC DatabaseMysql : public Database
{
friend class Trinity::OperatorNew<DatabaseMysql>;
+
public:
DatabaseMysql();
~DatabaseMysql();
+
//! Initializes Mysql and connects to a server.
/*! infoString should be formated like hostname;username;password;database. */
bool Initialize(const char *infoString);
@@ -49,18 +56,25 @@ class TRINITY_DLL_SPEC DatabaseMysql : public Database
bool BeginTransaction();
bool CommitTransaction();
bool RollbackTransaction();
+
operator bool () const { return mMysql != NULL; }
+
unsigned long escape_string(char *to, const char *from, unsigned long length);
using Database::escape_string;
+
// must be call before first query in thread
void ThreadStart();
// must be call before finish thread run
void ThreadEnd();
private:
ACE_Thread_Mutex mMutex;
+
ACE_Based::Thread * tranThread;
+
MYSQL *mMysql;
+
static size_t db_count;
+
bool _TransactionCmd(const char *sql);
bool _Query(const char *sql, MYSQL_RES **pResult, MYSQL_FIELD **pFields, uint64* pRowCount, uint32* pFieldCount);
};
diff --git a/src/shared/Database/Field.cpp b/src/shared/Database/Field.cpp
index 2467eabd448..9a1fbfa5178 100644
--- a/src/shared/Database/Field.cpp
+++ b/src/shared/Database/Field.cpp
@@ -17,21 +17,28 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+
#include "DatabaseEnv.h"
+
Field::Field() :
mValue(NULL), mType(DB_TYPE_UNKNOWN)
{
}
+
Field::Field(Field &f)
{
const char *value;
+
value = f.GetString();
+
if (value && (mValue = new char[strlen(value) + 1]))
strcpy(mValue, value);
else
mValue = NULL;
+
mType = f.GetType();
}
+
Field::Field(const char *value, enum Field::DataTypes type) :
mType(type)
{
@@ -40,13 +47,16 @@ mType(type)
else
mValue = NULL;
}
+
Field::~Field()
{
if(mValue) delete [] mValue;
}
+
void Field::SetValue(const char *value)
{
if(mValue) delete [] mValue;
+
if (value)
{
mValue = new char[strlen(value) + 1];
diff --git a/src/shared/Database/Field.h b/src/shared/Database/Field.h
index fd259423aef..d1238f838a5 100644
--- a/src/shared/Database/Field.h
+++ b/src/shared/Database/Field.h
@@ -17,11 +17,14 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+
#if !defined(FIELD_H)
#define FIELD_H
+
class Field
{
public:
+
enum DataTypes
{
DB_TYPE_UNKNOWN = 0x00,
@@ -30,11 +33,15 @@ class Field
DB_TYPE_FLOAT = 0x03,
DB_TYPE_BOOL = 0x04
};
+
Field();
Field(Field &f);
Field(const char *value, enum DataTypes type);
+
~Field();
+
enum DataTypes GetType() const { return mType; }
+
const char *GetString() const { return mValue; }
std::string GetCppString() const
{
@@ -69,8 +76,11 @@ class Field
else
return 0;
}
+
void SetType(enum DataTypes type) { mType = type; }
+
void SetValue(const char *value);
+
private:
char *mValue;
enum DataTypes mType;
diff --git a/src/shared/Database/MySQLDelayThread.h b/src/shared/Database/MySQLDelayThread.h
index f8dba08bddc..fcebe3fbd35 100644
--- a/src/shared/Database/MySQLDelayThread.h
+++ b/src/shared/Database/MySQLDelayThread.h
@@ -17,9 +17,12 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+
#ifndef __MYSQLDELAYTHREAD_H
#define __MYSQLDELAYTHREAD_H
+
#include "Database/SqlDelayThread.h"
+
class MySQLDelayThread : public SqlDelayThread
{
public:
diff --git a/src/shared/Database/QueryResult.h b/src/shared/Database/QueryResult.h
index 9d5bb57e4e9..f9f1a009833 100644
--- a/src/shared/Database/QueryResult.h
+++ b/src/shared/Database/QueryResult.h
@@ -17,39 +17,52 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+
#if !defined(QUERYRESULT_H)
#define QUERYRESULT_H
+
class TRINITY_DLL_SPEC QueryResult
{
public:
QueryResult(uint64 rowCount, uint32 fieldCount)
: mFieldCount(fieldCount), mRowCount(rowCount) {}
+
virtual ~QueryResult() {}
+
virtual bool NextRow() = 0;
+
Field *Fetch() const { return mCurrentRow; }
+
const Field & operator [] (int index) const { return mCurrentRow[index]; }
+
uint32 GetFieldCount() const { return mFieldCount; }
uint64 GetRowCount() const { return mRowCount; }
+
protected:
Field *mCurrentRow;
uint32 mFieldCount;
uint64 mRowCount;
};
+
typedef std::vector<std::string> QueryFieldNames;
+
class MANGOS_DLL_SPEC QueryNamedResult
{
public:
explicit QueryNamedResult(QueryResult* query, QueryFieldNames const& names) : mQuery(query), mFieldNames(names) {}
~QueryNamedResult() { delete mQuery; }
+
// compatible interface with QueryResult
bool NextRow() { return mQuery->NextRow(); }
Field *Fetch() const { return mQuery->Fetch(); }
uint32 GetFieldCount() const { return mQuery->GetFieldCount(); }
uint64 GetRowCount() const { return mQuery->GetRowCount(); }
Field const& operator[] (int index) const { return (*mQuery)[index]; }
+
// named access
Field const& operator[] (const std::string &name) const { return mQuery->Fetch()[GetField_idx(name)]; }
QueryFieldNames const& GetFieldNames() const { return mFieldNames; }
+
uint32 GetField_idx(const std::string &name) const
{
for(size_t idx = 0; idx < mFieldNames.size(); ++idx)
@@ -60,9 +73,11 @@ class MANGOS_DLL_SPEC QueryNamedResult
ASSERT(false && "unknown field name");
return uint32(-1);
}
+
protected:
QueryResult *mQuery;
QueryFieldNames mFieldNames;
};
+
#endif
diff --git a/src/shared/Database/QueryResultMysql.cpp b/src/shared/Database/QueryResultMysql.cpp
index ef8a77ec002..2e4738469c9 100644
--- a/src/shared/Database/QueryResultMysql.cpp
+++ b/src/shared/Database/QueryResultMysql.cpp
@@ -17,35 +17,47 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+
#ifndef DO_POSTGRESQL
+
#include "DatabaseEnv.h"
+
QueryResultMysql::QueryResultMysql(MYSQL_RES *result, MYSQL_FIELD *fields, uint64 rowCount, uint32 fieldCount) :
QueryResult(rowCount, fieldCount), mResult(result)
{
+
mCurrentRow = new Field[mFieldCount];
ASSERT(mCurrentRow);
+
for (uint32 i = 0; i < mFieldCount; i++)
mCurrentRow[i].SetType(ConvertNativeType(fields[i].type));
}
+
QueryResultMysql::~QueryResultMysql()
{
EndQuery();
}
+
bool QueryResultMysql::NextRow()
{
MYSQL_ROW row;
+
if (!mResult)
return false;
+
row = mysql_fetch_row(mResult);
if (!row)
{
EndQuery();
return false;
}
+
for (uint32 i = 0; i < mFieldCount; i++)
mCurrentRow[i].SetValue(row[i]);
+
return true;
}
+
void QueryResultMysql::EndQuery()
{
if (mCurrentRow)
@@ -53,12 +65,14 @@ void QueryResultMysql::EndQuery()
delete [] mCurrentRow;
mCurrentRow = 0;
}
+
if (mResult)
{
mysql_free_result(mResult);
mResult = 0;
}
}
+
enum Field::DataTypes QueryResultMysql::ConvertNativeType(enum_field_types mysqlType) const
{
switch (mysqlType)
@@ -75,6 +89,7 @@ enum Field::DataTypes QueryResultMysql::ConvertNativeType(enum_field_types mysql
case FIELD_TYPE_NULL:
return Field::DB_TYPE_STRING;
case FIELD_TYPE_TINY:
+
case FIELD_TYPE_SHORT:
case FIELD_TYPE_LONG:
case FIELD_TYPE_INT24:
diff --git a/src/shared/Database/QueryResultMysql.h b/src/shared/Database/QueryResultMysql.h
index fb9d422ebf2..89aceb12b13 100644
--- a/src/shared/Database/QueryResultMysql.h
+++ b/src/shared/Database/QueryResultMysql.h
@@ -17,9 +17,12 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+
#ifndef DO_POSTGRESQL
+
#if !defined(QUERYRESULTMYSQL_H)
#define QUERYRESULTMYSQL_H
+
#ifdef WIN32
#define FD_SETSIZE 1024
#include <winsock2.h>
@@ -27,15 +30,20 @@
#else
#include <mysql.h>
#endif
+
class QueryResultMysql : public QueryResult
{
public:
QueryResultMysql(MYSQL_RES *result, MYSQL_FIELD *fields, uint64 rowCount, uint32 fieldCount);
+
~QueryResultMysql();
+
bool NextRow();
+
private:
enum Field::DataTypes ConvertNativeType(enum_field_types mysqlType) const;
void EndQuery();
+
MYSQL_RES *mResult;
};
#endif
diff --git a/src/shared/Database/SQLStorage.cpp b/src/shared/Database/SQLStorage.cpp
index e4de05c7c77..372baafe278 100644
--- a/src/shared/Database/SQLStorage.cpp
+++ b/src/shared/Database/SQLStorage.cpp
@@ -17,13 +17,16 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+
#include "SQLStorage.h"
#include "SQLStorageImpl.h"
+
#ifdef DO_POSTGRESQL
extern DatabasePostgre WorldDatabase;
#else
extern DatabaseMysql WorldDatabase;
#endif
+
const char CreatureInfosrcfmt[]="iiiiiiiisssiiiiiiiiiiffiffiifiiiiiiiiiiffiiiiiiiiiiiiiiiiiiiiiiiisiiffliiiiiliiis";
const char CreatureInfodstfmt[]="iiiiiiiisssiiiiiiiiiiffiffiifiiiiiiiiiiffiiiiiiiiiiiiiiiiiiiiiiiisiiffliiiiiliiii";
const char CreatureDataAddonInfofmt[]="iiiiiiis";
@@ -37,6 +40,7 @@ const char ItemPrototypedstfmt[]="iiiisiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
const char PageTextfmt[]="isi";
const char InstanceTemplatesrcfmt[]="iiiiiiffffs";
const char InstanceTemplatedstfmt[]="iiiiiiffffi";
+
SQLStorage sCreatureStorage(CreatureInfosrcfmt, CreatureInfodstfmt, "entry","creature_template");
SQLStorage sCreatureDataAddonStorage(CreatureDataAddonInfofmt,"guid","creature_addon");
SQLStorage sCreatureModelStorage(CreatureModelfmt,"modelid","creature_model_info");
@@ -46,6 +50,7 @@ SQLStorage sGOStorage(GameObjectInfosrcfmt, GameObjectInfodstfmt, "entry","gameo
SQLStorage sItemStorage(ItemPrototypesrcfmt, ItemPrototypedstfmt, "entry","item_template");
SQLStorage sPageTextStore(PageTextfmt,"entry","page_text");
SQLStorage sInstanceTemplate(InstanceTemplatesrcfmt, InstanceTemplatedstfmt, "map","instance_template");
+
void SQLStorage::Free ()
{
uint32 offset=0;
@@ -55,6 +60,7 @@ void SQLStorage::Free ()
for(uint32 y=0;y<MaxEntry;y++)
if(pIndex[y])
delete [] *(char**)((char*)(pIndex[y])+offset);
+
offset += sizeof(char*);
}
else if (dst_format[x]==FT_LOGIC)
@@ -63,9 +69,11 @@ void SQLStorage::Free ()
offset += sizeof(char);
else
offset += 4;
+
delete [] pIndex;
delete [] data;
}
+
void SQLStorage::Load()
{
SQLStorageLoader loader;
diff --git a/src/shared/Database/SQLStorage.h b/src/shared/Database/SQLStorage.h
index 96f817c64e7..cc165af532e 100644
--- a/src/shared/Database/SQLStorage.h
+++ b/src/shared/Database/SQLStorage.h
@@ -17,21 +17,27 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+
#ifndef SQLSTORAGE_H
#define SQLSTORAGE_H
+
#include "Common.h"
#include "Database/DatabaseEnv.h"
+
class SQLStorage
{
template<class T>
friend struct SQLStorageLoaderBase;
+
public:
+
SQLStorage(const char* fmt, const char * _entry_field, const char * sqlname)
{
src_format = fmt;
dst_format = fmt;
init(_entry_field, sqlname);
}
+
SQLStorage(const char* src_fmt, const char* dst_fmt, const char * _entry_field, const char * sqlname)
{
src_format = src_fmt;
@@ -39,10 +45,12 @@ class SQLStorage
init(_entry_field, sqlname);
}
+
~SQLStorage()
{
Free();
}
+
template<class T>
T const* LookupEntry(uint32 id) const
{
@@ -52,12 +60,16 @@ class SQLStorage
return NULL;
return reinterpret_cast<T const*>(pIndex[id]);
}
+
uint32 RecordCount;
uint32 MaxEntry;
uint32 iNumFields;
+
char const* GetTableName() const { return table; }
+
void Load();
void Free();
+
private:
void init(const char * _entry_field, const char * sqlname)
{
@@ -68,7 +80,9 @@ class SQLStorage
iNumFields = strlen(src_format);
MaxEntry = 0;
}
+
char** pIndex;
+
char *data;
const char *src_format;
const char *dst_format;
@@ -76,11 +90,13 @@ class SQLStorage
const char *entry_field;
//bool HasString;
};
+
template <class T>
struct SQLStorageLoaderBase
{
public:
void Load(SQLStorage &storage);
+
template<class S, class D>
void convert(uint32 field_pos, S src, D &dst);
template<class S>
@@ -88,13 +104,16 @@ struct SQLStorageLoaderBase
template<class D>
void convert_from_str(uint32 field_pos, char * src, D& dst);
void convert_str_to_str(uint32 field_pos, char *src, char *&dst);
+
private:
template<class V>
void storeValue(V value, SQLStorage &store, char *p, int x, uint32 &offset);
void storeValue(char * value, SQLStorage &store, char *p, int x, uint32 &offset);
};
+
struct SQLStorageLoader : public SQLStorageLoaderBase<SQLStorageLoader>
{
};
+
#endif
diff --git a/src/shared/Database/SQLStorageImpl.h b/src/shared/Database/SQLStorageImpl.h
index c229327a0ec..b511bdad68c 100644
--- a/src/shared/Database/SQLStorageImpl.h
+++ b/src/shared/Database/SQLStorageImpl.h
@@ -15,15 +15,18 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+
#include "ProgressBar.h"
#include "Log.h"
#include "DBCFileLoader.h"
+
template<class T>
template<class S, class D>
void SQLStorageLoaderBase<T>::convert(uint32 /*field_pos*/, S src, D &dst)
{
dst = D(src);
}
+
template<class T>
void SQLStorageLoaderBase<T>::convert_str_to_str(uint32 /*field_pos*/, char *src, char *&dst)
{
@@ -39,6 +42,7 @@ void SQLStorageLoaderBase<T>::convert_str_to_str(uint32 /*field_pos*/, char *src
memcpy(dst, src, l);
}
}
+
template<class T>
template<class S>
void SQLStorageLoaderBase<T>::convert_to_str(uint32 /*field_pos*/, S /*src*/, char * & dst)
@@ -46,12 +50,14 @@ void SQLStorageLoaderBase<T>::convert_to_str(uint32 /*field_pos*/, S /*src*/, ch
dst = new char[1];
*dst = 0;
}
+
template<class T>
template<class D>
void SQLStorageLoaderBase<T>::convert_from_str(uint32 /*field_pos*/, char * /*src*/, D& dst)
{
dst = 0;
}
+
template<class T>
template<class V>
void SQLStorageLoaderBase<T>::storeValue(V value, SQLStorage &store, char *p, int x, uint32 &offset)
@@ -81,6 +87,7 @@ void SQLStorageLoaderBase<T>::storeValue(V value, SQLStorage &store, char *p, in
break;
}
}
+
template<class T>
void SQLStorageLoaderBase<T>::storeValue(char * value, SQLStorage &store, char *p, int x, uint32 &offset)
{
@@ -109,6 +116,7 @@ void SQLStorageLoaderBase<T>::storeValue(char * value, SQLStorage &store, char *
break;
}
}
+
template<class T>
void SQLStorageLoaderBase<T>::Load(SQLStorage &store)
{
@@ -120,8 +128,10 @@ void SQLStorageLoaderBase<T>::Load(SQLStorage &store)
sLog.outError("Error loading %s table (not exist?)\n", store.table);
exit(1); // Stop server at loading non exited table or not accessable table
}
+
maxi = (*result)[0].GetUInt32()+1;
delete result;
+
result = WorldDatabase.PQuery("SELECT COUNT(*) FROM %s", store.table);
if(result)
{
@@ -131,15 +141,19 @@ void SQLStorageLoaderBase<T>::Load(SQLStorage &store)
}
else
store.RecordCount = 0;
+
result = WorldDatabase.PQuery("SELECT * FROM %s", store.table);
+
if(!result)
{
sLog.outError("%s table is empty!\n", store.table);
store.RecordCount = 0;
return;
}
+
uint32 recordsize = 0;
uint32 offset = 0;
+
if(store.iNumFields != result->GetFieldCount())
{
store.RecordCount = 0;
@@ -147,6 +161,7 @@ void SQLStorageLoaderBase<T>::Load(SQLStorage &store)
delete result;
exit(1); // Stop server at loading broken or non-compatible table.
}
+
//get struct size
uint32 sc=0;
uint32 bo=0;
@@ -159,8 +174,10 @@ void SQLStorageLoaderBase<T>::Load(SQLStorage &store)
else if (store.dst_format[x]==FT_BYTE)
++bb;
recordsize=(store.iNumFields-sc-bo-bb)*4+sc*sizeof(char*)+bo*sizeof(bool)+bb*sizeof(char);
+
char** newIndex=new char*[maxi];
memset(newIndex,0,maxi*sizeof(char*));
+
char * _data= new char[store.RecordCount *recordsize];
uint32 count=0;
barGoLink bar( store.RecordCount );
@@ -170,6 +187,7 @@ void SQLStorageLoaderBase<T>::Load(SQLStorage &store)
bar.step();
char *p=(char*)&_data[recordsize*count];
newIndex[fields[0].GetUInt32()]=p;
+
offset=0;
for(uint32 x = 0; x < store.iNumFields; x++)
switch(store.src_format[x])
@@ -187,7 +205,9 @@ void SQLStorageLoaderBase<T>::Load(SQLStorage &store)
}
++count;
}while( result->NextRow() );
+
delete result;
+
store.pIndex = newIndex;
store.MaxEntry = maxi;
store.data = _data;
diff --git a/src/shared/Database/SqlDelayThread.cpp b/src/shared/Database/SqlDelayThread.cpp
index bca8dcd8cd6..88b6b85df70 100644
--- a/src/shared/Database/SqlDelayThread.cpp
+++ b/src/shared/Database/SqlDelayThread.cpp
@@ -17,17 +17,21 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+
#include "Database/SqlDelayThread.h"
#include "Database/SqlOperations.h"
#include "DatabaseEnv.h"
+
SqlDelayThread::SqlDelayThread(Database* db) : m_dbEngine(db), m_running(true)
{
}
+
void SqlDelayThread::run()
{
#ifndef DO_POSTGRESQL
mysql_thread_init();
#endif
+
while (m_running)
{
// if the running state gets turned off while sleeping
@@ -40,10 +44,12 @@ void SqlDelayThread::run()
delete s;
}
}
+
#ifndef DO_POSTGRESQL
mysql_thread_end();
#endif
}
+
void SqlDelayThread::Stop()
{
m_running = false;
diff --git a/src/shared/Database/SqlDelayThread.h b/src/shared/Database/SqlDelayThread.h
index 422b01ac650..3c24d3525b7 100644
--- a/src/shared/Database/SqlDelayThread.h
+++ b/src/shared/Database/SqlDelayThread.h
@@ -17,26 +17,34 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+
#ifndef __SQLDELAYTHREAD_H
#define __SQLDELAYTHREAD_H
+
#include "ace/Thread_Mutex.h"
#include "LockedQueue.h"
#include "Threading.h"
+
class Database;
class SqlOperation;
+
class SqlDelayThread : public ACE_Based::Runnable
{
typedef ACE_Based::LockedQueue<SqlOperation*, ACE_Thread_Mutex> SqlQueue;
+
private:
SqlQueue m_sqlQueue; ///< Queue of SQL statements
Database* m_dbEngine; ///< Pointer to used Database engine
volatile bool m_running;
+
SqlDelayThread();
public:
SqlDelayThread(Database* db);
+
///< Put sql statement to delay queue
bool Delay(SqlOperation* sql) { m_sqlQueue.add(sql); return true; }
+
virtual void Stop(); ///< Stop event
virtual void run(); ///< Main Thread loop
};
diff --git a/src/shared/Database/SqlOperations.cpp b/src/shared/Database/SqlOperations.cpp
index 9ca698d733e..396f2e36bc2 100644
--- a/src/shared/Database/SqlOperations.cpp
+++ b/src/shared/Database/SqlOperations.cpp
@@ -17,16 +17,20 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+
#include "SqlOperations.h"
#include "SqlDelayThread.h"
#include "DatabaseEnv.h"
#include "DatabaseImpl.h"
+
/// ---- ASYNC STATEMENTS / TRANSACTIONS ----
+
void SqlStatement::Execute(Database *db)
{
/// just do it
db->DirectExecute(m_sql);
}
+
void SqlTransaction::Execute(Database *db)
{
if(m_queue.empty())
@@ -36,6 +40,7 @@ void SqlTransaction::Execute(Database *db)
{
char const *sql = m_queue.front();
m_queue.pop();
+
if(!db->DirectExecute(sql))
{
free((void*)const_cast<char*>(sql));
@@ -47,11 +52,14 @@ void SqlTransaction::Execute(Database *db)
}
return;
}
+
free((void*)const_cast<char*>(sql));
}
db->DirectExecute("COMMIT");
}
+
/// ---- ASYNC QUERIES ----
+
void SqlQuery::Execute(Database *db)
{
if(!m_callback || !m_queue)
@@ -61,6 +69,7 @@ void SqlQuery::Execute(Database *db)
/// add the callback to the sql result queue of the thread it originated from
m_queue->add(m_callback);
}
+
void SqlResultQueue::Update()
{
/// execute the callbacks waiting in the synchronization queue
@@ -71,16 +80,19 @@ void SqlResultQueue::Update()
delete callback;
}
}
+
bool SqlQueryHolder::Execute(Trinity::IQueryCallback * callback, SqlDelayThread *thread, SqlResultQueue *queue)
{
if(!callback || !thread || !queue)
return false;
+
/// delay the execution of the queries, sync them with the delay thread
/// which will in turn resync on execution (via the queue) and call back
SqlQueryHolderEx *holderEx = new SqlQueryHolderEx(this, callback, queue);
thread->Delay(holderEx);
return true;
}
+
bool SqlQueryHolder::SetQuery(size_t index, const char *sql)
{
if(m_queries.size() <= index)
@@ -88,16 +100,19 @@ bool SqlQueryHolder::SetQuery(size_t index, const char *sql)
sLog.outError("Query index (%u) out of range (size: %u) for query: %s",index,(uint32)m_queries.size(),sql);
return false;
}
+
if(m_queries[index].first != NULL)
{
sLog.outError("Attempt assign query to holder index (%u) where other query stored (Old: [%s] New: [%s])",
index,m_queries[index].first,sql);
return false;
}
+
/// not executed yet, just stored (it's not called a holder for nothing)
m_queries[index] = SqlResultPair(strdup(sql), NULL);
return true;
}
+
bool SqlQueryHolder::SetPQuery(size_t index, const char *format, ...)
{
if(!format)
@@ -105,18 +120,22 @@ bool SqlQueryHolder::SetPQuery(size_t index, const char *format, ...)
sLog.outError("Query (index: %u) is empty.",index);
return false;
}
+
va_list ap;
char szQuery [MAX_QUERY_LEN];
va_start(ap, format);
int res = vsnprintf( szQuery, MAX_QUERY_LEN, format, ap );
va_end(ap);
+
if(res==-1)
{
sLog.outError("SQL Query truncated (and not execute) for format: %s",format);
return false;
}
+
return SetQuery(index,szQuery);
}
+
QueryResult* SqlQueryHolder::GetResult(size_t index)
{
if(index < m_queries.size())
@@ -133,12 +152,14 @@ QueryResult* SqlQueryHolder::GetResult(size_t index)
else
return NULL;
}
+
void SqlQueryHolder::SetResult(size_t index, QueryResult *result)
{
/// store the result in the holder
if(index < m_queries.size())
m_queries[index].second = result;
}
+
SqlQueryHolder::~SqlQueryHolder()
{
for(size_t i = 0; i < m_queries.size(); i++)
@@ -153,23 +174,28 @@ SqlQueryHolder::~SqlQueryHolder()
}
}
}
+
void SqlQueryHolder::SetSize(size_t size)
{
/// to optimize push_back, reserve the number of queries about to be executed
m_queries.resize(size);
}
+
void SqlQueryHolderEx::Execute(Database *db)
{
if(!m_holder || !m_callback || !m_queue)
return;
+
/// we can do this, we are friends
std::vector<SqlQueryHolder::SqlResultPair> &queries = m_holder->m_queries;
+
for(size_t i = 0; i < queries.size(); i++)
{
/// execute all queries in the holder and pass the results
char const *sql = queries[i].first;
if(sql) m_holder->SetResult(i, db->Query(sql));
}
+
/// sync with the caller thread
m_queue->add(m_callback);
}
diff --git a/src/shared/Database/SqlOperations.h b/src/shared/Database/SqlOperations.h
index 164c7258ec3..e91d83b6611 100644
--- a/src/shared/Database/SqlOperations.h
+++ b/src/shared/Database/SqlOperations.h
@@ -17,16 +17,22 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+
#ifndef __SQLOPERATIONS_H
#define __SQLOPERATIONS_H
+
#include "Common.h"
+
#include "ace/Thread_Mutex.h"
#include "LockedQueue.h"
#include <queue>
#include "Utilities/Callback.h"
+
/// ---- BASE ---
+
class Database;
class SqlDelayThread;
+
class SqlOperation
{
public:
@@ -34,7 +40,9 @@ class SqlOperation
virtual void Execute(Database *db) = 0;
virtual ~SqlOperation() {}
};
+
/// ---- ASYNC STATEMENTS / TRANSACTIONS ----
+
class SqlStatement : public SqlOperation
{
private:
@@ -44,6 +52,7 @@ class SqlStatement : public SqlOperation
~SqlStatement() { void* tofree = const_cast<char*>(m_sql); free(tofree); }
void Execute(Database *db);
};
+
class SqlTransaction : public SqlOperation
{
private:
@@ -53,18 +62,22 @@ class SqlTransaction : public SqlOperation
void DelayExecute(const char *sql) { m_queue.push(strdup(sql)); }
void Execute(Database *db);
};
+
/// ---- ASYNC QUERIES ----
+
class SqlQuery; /// contains a single async query
class QueryResult; /// the result of one
class SqlResultQueue; /// queue for thread sync
class SqlQueryHolder; /// groups several async quries
class SqlQueryHolderEx; /// points to a holder, added to the delay thread
+
class SqlResultQueue : public ACE_Based::LockedQueue<MaNGOS::IQueryCallback* , ACE_Thread_Mutex>
{
public:
SqlResultQueue() {}
void Update();
};
+
class SqlQuery : public SqlOperation
{
private:
@@ -77,6 +90,7 @@ class SqlQuery : public SqlOperation
~SqlQuery() { void* tofree = const_cast<char*>(m_sql); free(tofree); }
void Execute(Database *db);
};
+
class SqlQueryHolder
{
friend class SqlQueryHolderEx;
@@ -93,6 +107,7 @@ class SqlQueryHolder
void SetResult(size_t index, QueryResult *result);
bool Execute(Trinity::IQueryCallback * callback, SqlDelayThread *thread, SqlResultQueue *queue);
};
+
class SqlQueryHolderEx : public SqlOperation
{
private: