/* * Copyright (C) 2005-2012 MaNGOS * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * 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/UnorderedMapSet.h" #include "Database/SqlDelayThread.h" #include #include "Policies/ThreadingModel.h" #include #include #include "SqlPreparedStatement.h" class SqlTransaction; class SqlResultQueue; class SqlQueryHolder; class SqlStmtParameters; class SqlParamBinder; class Database; #define MAX_QUERY_LEN 32*1024 // class MANGOS_DLL_SPEC SqlConnection { public: virtual ~SqlConnection() {} // method for initializing DB connection virtual bool Initialize(const char* infoString) = 0; // public methods for making queries virtual QueryResult* Query(const char* sql) = 0; virtual QueryNamedResult* QueryNamed(const char* sql) = 0; // public methods for making requests virtual bool Execute(const char* sql) = 0; // escape string generation virtual unsigned long escape_string(char* to, const char* from, unsigned long length) { strncpy(to, from, length); return length; } // nothing do if DB not support transactions virtual bool BeginTransaction() { return true; } virtual bool CommitTransaction() { return true; } // can't rollback without transaction support virtual bool RollbackTransaction() { return true; } // methods to work with prepared statements bool ExecuteStmt(int nIndex, const SqlStmtParameters& id); // SqlConnection object lock class Lock { public: Lock(SqlConnection* conn) : m_pConn(conn) { m_pConn->m_mutex.acquire(); } ~Lock() { m_pConn->m_mutex.release(); } SqlConnection* operator->() const { return m_pConn; } private: SqlConnection* const m_pConn; }; // get DB object Database& DB() { return m_db; } protected: SqlConnection(Database& db) : m_db(db) {} virtual SqlPreparedStatement* CreateStatement(const std::string& fmt); // allocate prepared statement and return statement ID SqlPreparedStatement* GetStmt(int nIndex); Database& m_db; // free prepared statements objects void FreePreparedStatements(); private: typedef ACE_Recursive_Thread_Mutex LOCK_TYPE; LOCK_TYPE m_mutex; typedef std::vector StmtHolder; StmtHolder m_holder; }; class MANGOS_DLL_SPEC Database { public: virtual ~Database(); virtual bool Initialize(const char* infoString, int nConns = 1); // start worker thread for async DB request execution virtual void InitDelayThread(); // stop worker thread virtual void HaltDelayThread(); /// Synchronous DB queries inline QueryResult* Query(const char* sql) { SqlConnection::Lock guard(getQueryConnection()); return guard->Query(sql); } inline QueryNamedResult* QueryNamed(const char* sql) { SqlConnection::Lock guard(getQueryConnection()); return guard->QueryNamed(sql); } QueryResult* PQuery(const char* format, ...) ATTR_PRINTF(2, 3); QueryNamedResult* PQueryNamed(const char* format, ...) ATTR_PRINTF(2, 3); inline bool DirectExecute(const char* sql) { if (!m_pAsyncConn) return false; SqlConnection::Lock guard(m_pAsyncConn); return guard->Execute(sql); } bool DirectPExecute(const char* format, ...) ATTR_PRINTF(2, 3); /// Async queries and query holders, implemented in DatabaseImpl.h // Query / member template bool AsyncQuery(Class* object, void (Class::*method)(QueryResult*), const char* sql); template bool AsyncQuery(Class* object, void (Class::*method)(QueryResult*, ParamType1), ParamType1 param1, const char* sql); template bool AsyncQuery(Class* object, void (Class::*method)(QueryResult*, ParamType1, ParamType2), ParamType1 param1, ParamType2 param2, const char* sql); template bool AsyncQuery(Class* object, void (Class::*method)(QueryResult*, ParamType1, ParamType2, ParamType3), ParamType1 param1, ParamType2 param2, ParamType3 param3, const char* sql); // Query / static template bool AsyncQuery(void (*method)(QueryResult*, ParamType1), ParamType1 param1, const char* sql); template bool AsyncQuery(void (*method)(QueryResult*, ParamType1, ParamType2), ParamType1 param1, ParamType2 param2, const char* sql); template bool AsyncQuery(void (*method)(QueryResult*, ParamType1, ParamType2, ParamType3), ParamType1 param1, ParamType2 param2, ParamType3 param3, const char* sql); // PQuery / member template bool AsyncPQuery(Class* object, void (Class::*method)(QueryResult*), const char* format, ...) ATTR_PRINTF(4, 5); template bool AsyncPQuery(Class* object, void (Class::*method)(QueryResult*, ParamType1), ParamType1 param1, const char* format, ...) ATTR_PRINTF(5, 6); template bool AsyncPQuery(Class* object, void (Class::*method)(QueryResult*, ParamType1, ParamType2), ParamType1 param1, ParamType2 param2, const char* format, ...) ATTR_PRINTF(6, 7); template bool AsyncPQuery(Class* object, void (Class::*method)(QueryResult*, ParamType1, ParamType2, ParamType3), ParamType1 param1, ParamType2 param2, ParamType3 param3, const char* format, ...) ATTR_PRINTF(7, 8); // PQuery / static template bool AsyncPQuery(void (*method)(QueryResult*, ParamType1), ParamType1 param1, const char* format, ...) ATTR_PRINTF(4, 5); template bool AsyncPQuery(void (*method)(QueryResult*, ParamType1, ParamType2), ParamType1 param1, ParamType2 param2, const char* format, ...) ATTR_PRINTF(5, 6); template bool AsyncPQuery(void (*method)(QueryResult*, ParamType1, ParamType2, ParamType3), ParamType1 param1, ParamType2 param2, ParamType3 param3, const char* format, ...) ATTR_PRINTF(6, 7); template // QueryHolder bool DelayQueryHolder(Class* object, void (Class::*method)(QueryResult*, SqlQueryHolder*), SqlQueryHolder* holder); template bool DelayQueryHolder(Class* object, void (Class::*method)(QueryResult*, SqlQueryHolder*, ParamType1), SqlQueryHolder* holder, ParamType1 param1); bool Execute(const char* sql); bool PExecute(const char* format, ...) ATTR_PRINTF(2, 3); // Writes SQL commands to a LOG file (see mangosd.conf "LogSQL") bool PExecuteLog(const char* format, ...) ATTR_PRINTF(2, 3); bool BeginTransaction(); bool CommitTransaction(); bool RollbackTransaction(); // for sync transaction execution bool CommitTransactionDirect(); // PREPARED STATEMENT API // allocate index for prepared statement with SQL request 'fmt' SqlStatement CreateStatement(SqlStatementID& index, const char* fmt); // get prepared statement format string std::string GetStmtString(const int stmtId) const; operator bool () const { return m_pQueryConnections.size() && m_pAsyncConn != 0; } // escape string generation void escape_string(std::string& str); // must be called before first query in thread (one time for thread using one from existing Database objects) virtual void ThreadStart(); // must be called before finish thread run (one time for thread using one from existing Database objects) virtual void ThreadEnd(); // set database-wide result queue. also we should use object-bases and not thread-based result queues void ProcessResultQueue(); bool CheckRequiredField(char const* table_name, char const* required_name); uint32 GetPingIntervall() { return m_pingIntervallms; } // function to ping database connections void Ping(); // set this to allow async transactions // you should call it explicitly after your server successfully started up // NO ASYNC TRANSACTIONS DURING SERVER STARTUP - ONLY DURING RUNTIME!!! void AllowAsyncTransactions() { m_bAllowAsyncTransactions = true; } protected: Database() : m_pAsyncConn(NULL), m_pResultQueue(NULL), m_threadBody(NULL), m_delayThread(NULL), m_logSQL(false), m_pingIntervallms(0), m_nQueryConnPoolSize(1), m_bAllowAsyncTransactions(false), m_iStmtIndex(-1) { m_nQueryCounter = -1; } void StopServer(); // factory method to create SqlConnection objects virtual SqlConnection* CreateConnection() = 0; // factory method to create SqlDelayThread objects virtual SqlDelayThread* CreateDelayThread(); class MANGOS_DLL_SPEC TransHelper { public: TransHelper() : m_pTrans(NULL) {} ~TransHelper(); // initializes new SqlTransaction object SqlTransaction* init(); // gets pointer on current transaction object. Returns NULL if transaction was not initiated SqlTransaction* get() const { return m_pTrans; } // detaches SqlTransaction object allocated by init() function // next call to get() function will return NULL! // do not forget to destroy obtained SqlTransaction object! SqlTransaction* detach(); // destroyes SqlTransaction allocated by init() function void reset(); private: SqlTransaction* m_pTrans; }; // per-thread based storage for SqlTransaction object initialization - no locking is required typedef ACE_TSS DBTransHelperTSS; Database::DBTransHelperTSS m_TransStorage; ///< DB connections // round-robin connection selection SqlConnection* getQueryConnection(); // for now return one single connection for async requests SqlConnection* getAsyncConnection() const { return m_pAsyncConn; } friend class SqlStatement; // PREPARED STATEMENT API // query function for prepared statements bool ExecuteStmt(const SqlStatementID& id, SqlStmtParameters* params); bool DirectExecuteStmt(const SqlStatementID& id, SqlStmtParameters* params); // connection helper counters int m_nQueryConnPoolSize; // current size of query connection pool ACE_Atomic_Op m_nQueryCounter; // counter for connection selection // lets use pool of connections for sync queries typedef std::vector< SqlConnection* > SqlConnectionContainer; SqlConnectionContainer m_pQueryConnections; // only one single DB connection for transactions SqlConnection* m_pAsyncConn; SqlResultQueue* m_pResultQueue; ///< Transaction 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 bool m_bAllowAsyncTransactions; ///< flag which specifies if async transactions are enabled // PREPARED STATEMENT REGISTRY typedef ACE_Thread_Mutex LOCK_TYPE; typedef ACE_Guard LOCK_GUARD; mutable LOCK_TYPE m_stmtGuard; typedef UNORDERED_MAP PreparedStmtRegistry; PreparedStmtRegistry m_stmtRegistry; ///< int m_iStmtIndex; private: bool m_logSQL; std::string m_logsDir; uint32 m_pingIntervallms; }; #endif