diff options
author | Shauren <shauren.trinity@gmail.com> | 2017-05-12 18:49:51 +0200 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2017-05-12 18:50:27 +0200 |
commit | 7e538980a2b4fc6c74bde7bd456633d954272708 (patch) | |
tree | 73454d83035b0ddd099e4bc934222df60b66f597 /src/server/database | |
parent | 8fdf0778ca340d0bbf0e70dbf091d20c838981d3 (diff) |
Core/Database: Include cleanup
Diffstat (limited to 'src/server/database')
42 files changed, 1037 insertions, 876 deletions
diff --git a/src/server/database/Database/AdhocStatement.cpp b/src/server/database/Database/AdhocStatement.cpp index 644af01787b..93862db2fb4 100644 --- a/src/server/database/Database/AdhocStatement.cpp +++ b/src/server/database/Database/AdhocStatement.cpp @@ -16,7 +16,10 @@ */ #include "AdhocStatement.h" +#include "Errors.h" #include "MySQLConnection.h" +#include "QueryResult.h" +#include <cstring> /*! Basic, ad-hoc queries. */ BasicStatementTask::BasicStatementTask(const char* sql, bool async) : diff --git a/src/server/database/Database/AdhocStatement.h b/src/server/database/Database/AdhocStatement.h index e419908d175..5d85fa72cd6 100644 --- a/src/server/database/Database/AdhocStatement.h +++ b/src/server/database/Database/AdhocStatement.h @@ -18,12 +18,10 @@ #ifndef _ADHOCSTATEMENT_H #define _ADHOCSTATEMENT_H -#include <future> +#include "Define.h" +#include "DatabaseEnvFwd.h" #include "SQLOperation.h" -typedef std::future<QueryResult> QueryResultFuture; -typedef std::promise<QueryResult> QueryResultPromise; - /*! Raw, ad-hoc query. */ class TC_DATABASE_API BasicStatementTask : public SQLOperation { diff --git a/src/server/database/Database/DatabaseEnv.cpp b/src/server/database/Database/DatabaseEnv.cpp index 02541b06b0b..b5b866b43bf 100644 --- a/src/server/database/Database/DatabaseEnv.cpp +++ b/src/server/database/Database/DatabaseEnv.cpp @@ -17,7 +17,7 @@ #include "DatabaseEnv.h" -WorldDatabaseWorkerPool WorldDatabase; -CharacterDatabaseWorkerPool CharacterDatabase; -LoginDatabaseWorkerPool LoginDatabase; -HotfixDatabaseWorkerPool HotfixDatabase; +DatabaseWorkerPool<WorldDatabaseConnection> WorldDatabase; +DatabaseWorkerPool<CharacterDatabaseConnection> CharacterDatabase; +DatabaseWorkerPool<LoginDatabaseConnection> LoginDatabase; +DatabaseWorkerPool<HotfixDatabaseConnection> HotfixDatabase; diff --git a/src/server/database/Database/DatabaseEnv.h b/src/server/database/Database/DatabaseEnv.h index 317db0fce36..123d780ae3b 100644 --- a/src/server/database/Database/DatabaseEnv.h +++ b/src/server/database/Database/DatabaseEnv.h @@ -19,33 +19,27 @@ #ifndef DATABASEENV_H #define DATABASEENV_H -#include "Common.h" -#include "Errors.h" -#include "Log.h" +#include "Define.h" +#include "DatabaseWorkerPool.h" + +#include "Implementation/WorldDatabase.h" +#include "Implementation/CharacterDatabase.h" +#include "Implementation/LoginDatabase.h" +#include "Implementation/HotfixDatabase.h" #include "Field.h" +#include "PreparedStatement.h" +#include "QueryCallback.h" #include "QueryResult.h" - -#include "MySQLThreading.h" #include "Transaction.h" -#define _LIKE_ "LIKE" -#define _TABLE_SIM_ "`" -#define _CONCAT3_(A, B, C) "CONCAT( " A ", " B ", " C " )" -#define _OFFSET_ "LIMIT %d, 1" - -#include "Implementation/LoginDatabase.h" -#include "Implementation/CharacterDatabase.h" -#include "Implementation/WorldDatabase.h" -#include "Implementation/HotfixDatabase.h" - /// Accessor to the world database -TC_DATABASE_API extern WorldDatabaseWorkerPool WorldDatabase; +TC_DATABASE_API extern DatabaseWorkerPool<WorldDatabaseConnection> WorldDatabase; /// Accessor to the character database -TC_DATABASE_API extern CharacterDatabaseWorkerPool CharacterDatabase; +TC_DATABASE_API extern DatabaseWorkerPool<CharacterDatabaseConnection> CharacterDatabase; /// Accessor to the realm/login database -TC_DATABASE_API extern LoginDatabaseWorkerPool LoginDatabase; +TC_DATABASE_API extern DatabaseWorkerPool<LoginDatabaseConnection> LoginDatabase; /// Accessor to the hotfix database -TC_DATABASE_API extern HotfixDatabaseWorkerPool HotfixDatabase; +TC_DATABASE_API extern DatabaseWorkerPool<HotfixDatabaseConnection> HotfixDatabase; #endif diff --git a/src/server/database/Database/DatabaseEnvFwd.h b/src/server/database/Database/DatabaseEnvFwd.h new file mode 100644 index 00000000000..893dffaaace --- /dev/null +++ b/src/server/database/Database/DatabaseEnvFwd.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2008-2017 TrinityCore <http://www.trinitycore.org/> + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +#ifndef DatabaseEnvFwd_h__ +#define DatabaseEnvFwd_h__ + +#include <future> +#include <memory> + +class Field; + +class ResultSet; +typedef std::shared_ptr<ResultSet> QueryResult; +typedef std::future<QueryResult> QueryResultFuture; +typedef std::promise<QueryResult> QueryResultPromise; + +class PreparedStatement; + +class PreparedResultSet; +typedef std::shared_ptr<PreparedResultSet> PreparedQueryResult; +typedef std::future<PreparedQueryResult> PreparedQueryResultFuture; +typedef std::promise<PreparedQueryResult> PreparedQueryResultPromise; + +class QueryCallback; + +class Transaction; +typedef std::shared_ptr<Transaction> SQLTransaction; + +class SQLQueryHolder; +typedef std::future<SQLQueryHolder*> QueryResultHolderFuture; +typedef std::promise<SQLQueryHolder*> QueryResultHolderPromise; + +// mysql +typedef struct st_mysql MYSQL; +typedef struct st_mysql_res MYSQL_RES; +typedef struct st_mysql_field MYSQL_FIELD; +typedef struct st_mysql_bind MYSQL_BIND; +typedef struct st_mysql_stmt MYSQL_STMT; + +#endif // DatabaseEnvFwd_h__ diff --git a/src/server/database/Database/DatabaseLoader.cpp b/src/server/database/Database/DatabaseLoader.cpp index 9349132fa47..d7f30276be6 100644 --- a/src/server/database/Database/DatabaseLoader.cpp +++ b/src/server/database/Database/DatabaseLoader.cpp @@ -16,8 +16,10 @@ */ #include "DatabaseLoader.h" -#include "DBUpdater.h" #include "Config.h" +#include "DatabaseEnv.h" +#include "DBUpdater.h" +#include "Log.h" #include <mysqld_error.h> @@ -178,10 +180,10 @@ bool DatabaseLoader::Process(std::queue<Predicate>& queue) } template TC_DATABASE_API -DatabaseLoader& DatabaseLoader::AddDatabase<LoginDatabaseConnection>(LoginDatabaseWorkerPool&, std::string const&); +DatabaseLoader& DatabaseLoader::AddDatabase<LoginDatabaseConnection>(DatabaseWorkerPool<LoginDatabaseConnection>&, std::string const&); template TC_DATABASE_API -DatabaseLoader& DatabaseLoader::AddDatabase<CharacterDatabaseConnection>(CharacterDatabaseWorkerPool&, std::string const&); +DatabaseLoader& DatabaseLoader::AddDatabase<CharacterDatabaseConnection>(DatabaseWorkerPool<CharacterDatabaseConnection>&, std::string const&); template TC_DATABASE_API -DatabaseLoader& DatabaseLoader::AddDatabase<HotfixDatabaseConnection>(HotfixDatabaseWorkerPool&, std::string const&); +DatabaseLoader& DatabaseLoader::AddDatabase<HotfixDatabaseConnection>(DatabaseWorkerPool<HotfixDatabaseConnection>&, std::string const&); template TC_DATABASE_API -DatabaseLoader& DatabaseLoader::AddDatabase<WorldDatabaseConnection>(WorldDatabaseWorkerPool&, std::string const&); +DatabaseLoader& DatabaseLoader::AddDatabase<WorldDatabaseConnection>(DatabaseWorkerPool<WorldDatabaseConnection>&, std::string const&); diff --git a/src/server/database/Database/DatabaseLoader.h b/src/server/database/Database/DatabaseLoader.h index 1aa2e3622ac..b9f91ce265d 100644 --- a/src/server/database/Database/DatabaseLoader.h +++ b/src/server/database/Database/DatabaseLoader.h @@ -18,12 +18,15 @@ #ifndef DatabaseLoader_h__ #define DatabaseLoader_h__ -#include "DatabaseWorkerPool.h" -#include "DBUpdater.h" +#include "Define.h" #include <functional> -#include <stack> #include <queue> +#include <stack> +#include <string> + +template<class T> +class DatabaseWorkerPool; // A helper class to initiate all database worker pools, // handles updating, delays preparing of statements and cleans up on failure. diff --git a/src/server/database/Database/DatabaseWorker.cpp b/src/server/database/Database/DatabaseWorker.cpp index 54980863861..c26562b4ff1 100644 --- a/src/server/database/Database/DatabaseWorker.cpp +++ b/src/server/database/Database/DatabaseWorker.cpp @@ -15,7 +15,6 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "DatabaseEnv.h" #include "DatabaseWorker.h" #include "SQLOperation.h" #include "ProducerConsumerQueue.h" diff --git a/src/server/database/Database/DatabaseWorker.h b/src/server/database/Database/DatabaseWorker.h index 38444706656..1476a2b9e99 100644 --- a/src/server/database/Database/DatabaseWorker.h +++ b/src/server/database/Database/DatabaseWorker.h @@ -18,8 +18,12 @@ #ifndef _WORKERTHREAD_H #define _WORKERTHREAD_H +#include "Define.h" +#include <atomic> #include <thread> -#include "ProducerConsumerQueue.h" + +template <typename T> +class ProducerConsumerQueue; class MySQLConnection; class SQLOperation; @@ -37,7 +41,7 @@ class TC_DATABASE_API DatabaseWorker void WorkerThread(); std::thread _workerThread; - std::atomic_bool _cancelationToken; + std::atomic<bool> _cancelationToken; DatabaseWorker(DatabaseWorker const& right) = delete; DatabaseWorker& operator=(DatabaseWorker const& right) = delete; diff --git a/src/server/database/Database/DatabaseWorkerPool.cpp b/src/server/database/Database/DatabaseWorkerPool.cpp index aba2c573c4c..2af31c53a40 100644 --- a/src/server/database/Database/DatabaseWorkerPool.cpp +++ b/src/server/database/Database/DatabaseWorkerPool.cpp @@ -16,12 +16,37 @@ */ #include "DatabaseWorkerPool.h" -#include "DatabaseEnv.h" +#include "AdhocStatement.h" +#include "Common.h" +#include "Errors.h" +#include "Implementation/LoginDatabase.h" +#include "Implementation/WorldDatabase.h" +#include "Implementation/CharacterDatabase.h" +#include "Implementation/HotfixDatabase.h" +#include "Log.h" +#include "PreparedStatement.h" +#include "ProducerConsumerQueue.h" #include "QueryCallback.h" +#include "QueryHolder.h" +#include "QueryResult.h" +#include "SQLOperation.h" +#include "Transaction.h" +#include <mysql.h> +#include <mysqld_error.h> #define MIN_MYSQL_SERVER_VERSION 50100u #define MIN_MYSQL_CLIENT_VERSION 50100u +class PingOperation : public SQLOperation +{ + //! Operation for idle delaythreads + bool Execute() override + { + m_conn->Ping(); + return true; + } +}; + template <class T> DatabaseWorkerPool<T>::DatabaseWorkerPool() : _queue(new ProducerConsumerQueue<SQLOperation*>()), @@ -241,6 +266,12 @@ void DatabaseWorkerPool<T>::DirectCommitTransaction(SQLTransaction& transaction) } template <class T> +PreparedStatement* DatabaseWorkerPool<T>::GetPreparedStatement(PreparedStatementIndex index) +{ + return new PreparedStatement(index); +} + +template <class T> void DatabaseWorkerPool<T>::EscapeString(std::string& str) { if (str.empty()) @@ -313,6 +344,22 @@ uint32 DatabaseWorkerPool<T>::OpenConnections(InternalIndex type, uint8 numConne } template <class T> +unsigned long DatabaseWorkerPool<T>::EscapeString(char *to, const char *from, unsigned long length) +{ + if (!to || !from || !length) + return 0; + + return mysql_real_escape_string( + _connections[IDX_SYNCH].front()->GetHandle(), to, from, length); +} + +template <class T> +void DatabaseWorkerPool<T>::Enqueue(SQLOperation* op) +{ + _queue->Push(op); +} + +template <class T> T* DatabaseWorkerPool<T>::GetFreeConnection() { uint8 i = 0; @@ -330,6 +377,69 @@ T* DatabaseWorkerPool<T>::GetFreeConnection() return connection; } +template <class T> +char const* DatabaseWorkerPool<T>::GetDatabaseName() const +{ + return _connectionInfo->database.c_str(); +} + +template <class T> +void DatabaseWorkerPool<T>::Execute(const char* sql) +{ + if (Trinity::IsFormatEmptyOrNull(sql)) + return; + + BasicStatementTask* task = new BasicStatementTask(sql); + Enqueue(task); +} + +template <class T> +void DatabaseWorkerPool<T>::Execute(PreparedStatement* stmt) +{ + PreparedStatementTask* task = new PreparedStatementTask(stmt); + Enqueue(task); +} + +template <class T> +void DatabaseWorkerPool<T>::DirectExecute(const char* sql) +{ + if (Trinity::IsFormatEmptyOrNull(sql)) + return; + + T* connection = GetFreeConnection(); + connection->Execute(sql); + connection->Unlock(); +} + +template <class T> +void DatabaseWorkerPool<T>::DirectExecute(PreparedStatement* stmt) +{ + T* connection = GetFreeConnection(); + connection->Execute(stmt); + connection->Unlock(); + + //! Delete proxy-class. Not needed anymore + delete stmt; +} + +template <class T> +void DatabaseWorkerPool<T>::ExecuteOrAppend(SQLTransaction& trans, const char* sql) +{ + if (!trans) + Execute(sql); + else + trans->Append(sql); +} + +template <class T> +void DatabaseWorkerPool<T>::ExecuteOrAppend(SQLTransaction& trans, PreparedStatement* stmt) +{ + if (!trans) + Execute(stmt); + else + trans->Append(stmt); +} + template class TC_DATABASE_API DatabaseWorkerPool<LoginDatabaseConnection>; template class TC_DATABASE_API DatabaseWorkerPool<WorldDatabaseConnection>; template class TC_DATABASE_API DatabaseWorkerPool<CharacterDatabaseConnection>; diff --git a/src/server/database/Database/DatabaseWorkerPool.h b/src/server/database/Database/DatabaseWorkerPool.h index adca6b3f836..cc8d0302fb7 100644 --- a/src/server/database/Database/DatabaseWorkerPool.h +++ b/src/server/database/Database/DatabaseWorkerPool.h @@ -18,32 +18,18 @@ #ifndef _DATABASEWORKERPOOL_H #define _DATABASEWORKERPOOL_H -#include "Common.h" -#include "MySQLConnection.h" -#include "Transaction.h" -#include "DatabaseWorker.h" -#include "PreparedStatement.h" -#include "Log.h" -#include "QueryResult.h" -#include "QueryHolder.h" -#include "AdhocStatement.h" +#include "Define.h" +#include "DatabaseEnvFwd.h" #include "StringFormat.h" - -#include <mysqld_error.h> -#include <memory> #include <array> +#include <string> +#include <vector> -class QueryCallback; +template <typename T> +class ProducerConsumerQueue; -class PingOperation : public SQLOperation -{ - //! Operation for idle delaythreads - bool Execute() override - { - m_conn->Ping(); - return true; - } -}; +class SQLOperation; +struct MySQLConnectionInfo; template <class T> class DatabaseWorkerPool @@ -82,14 +68,7 @@ class DatabaseWorkerPool //! Enqueues a one-way SQL operation in string format that will be executed asynchronously. //! This method should only be used for queries that are only executed once, e.g during startup. - void Execute(const char* sql) - { - if (Trinity::IsFormatEmptyOrNull(sql)) - return; - - BasicStatementTask* task = new BasicStatementTask(sql); - Enqueue(task); - } + void Execute(const char* sql); //! Enqueues a one-way SQL operation in string format -with variable args- that will be executed asynchronously. //! This method should only be used for queries that are only executed once, e.g during startup. @@ -104,11 +83,7 @@ class DatabaseWorkerPool //! Enqueues a one-way SQL operation in prepared statement format that will be executed asynchronously. //! Statement must be prepared with CONNECTION_ASYNC flag. - void Execute(PreparedStatement* stmt) - { - PreparedStatementTask* task = new PreparedStatementTask(stmt); - Enqueue(task); - } + void Execute(PreparedStatement* stmt); /** Direct synchronous one-way statement methods. @@ -116,15 +91,7 @@ class DatabaseWorkerPool //! Directly executes a one-way SQL operation in string format, that will block the calling thread until finished. //! This method should only be used for queries that are only executed once, e.g during startup. - void DirectExecute(const char* sql) - { - if (Trinity::IsFormatEmptyOrNull(sql)) - return; - - T* connection = GetFreeConnection(); - connection->Execute(sql); - connection->Unlock(); - } + void DirectExecute(const char* sql); //! Directly executes a one-way SQL operation in string format -with variable args-, that will block the calling thread until finished. //! This method should only be used for queries that are only executed once, e.g during startup. @@ -139,15 +106,7 @@ class DatabaseWorkerPool //! Directly executes a one-way SQL operation in prepared statement format, that will block the calling thread until finished. //! Statement must be prepared with the CONNECTION_SYNCH flag. - void DirectExecute(PreparedStatement* stmt) - { - T* connection = GetFreeConnection(); - connection->Execute(stmt); - connection->Unlock(); - - //! Delete proxy-class. Not needed anymore - delete stmt; - } + void DirectExecute(PreparedStatement* stmt); /** Synchronous query (with resultset) methods. @@ -218,25 +177,13 @@ class DatabaseWorkerPool //! were appended to the transaction will be respected during execution. void DirectCommitTransaction(SQLTransaction& transaction); - //! Method used to execute prepared statements in a diverse context. + //! Method used to execute ad-hoc statements in a diverse context. //! Will be wrapped in a transaction if valid object is present, otherwise executed standalone. - void ExecuteOrAppend(SQLTransaction& trans, PreparedStatement* stmt) - { - if (!trans) - Execute(stmt); - else - trans->Append(stmt); - } + void ExecuteOrAppend(SQLTransaction& trans, const char* sql); - //! Method used to execute ad-hoc statements in a diverse context. + //! Method used to execute prepared statements in a diverse context. //! Will be wrapped in a transaction if valid object is present, otherwise executed standalone. - void ExecuteOrAppend(SQLTransaction& trans, const char* sql) - { - if (!trans) - Execute(sql); - else - trans->Append(sql); - } + void ExecuteOrAppend(SQLTransaction& trans, PreparedStatement* stmt); /** Other @@ -247,10 +194,7 @@ class DatabaseWorkerPool //! Automanaged (internally) pointer to a prepared statement object for usage in upper level code. //! Pointer is deleted in this->DirectExecute(PreparedStatement*), this->Query(PreparedStatement*) or PreparedStatementTask::~PreparedStatementTask. //! This object is not tied to the prepared statement on the MySQL context yet until execution. - PreparedStatement* GetPreparedStatement(PreparedStatementIndex index) - { - return new PreparedStatement(index); - } + PreparedStatement* GetPreparedStatement(PreparedStatementIndex index); //! Apply escape string'ing for current collation. (utf8) void EscapeString(std::string& str); @@ -261,28 +205,15 @@ class DatabaseWorkerPool private: uint32 OpenConnections(InternalIndex type, uint8 numConnections); - unsigned long EscapeString(char *to, const char *from, unsigned long length) - { - if (!to || !from || !length) - return 0; - - return mysql_real_escape_string( - _connections[IDX_SYNCH].front()->GetHandle(), to, from, length); - } + unsigned long EscapeString(char *to, const char *from, unsigned long length); - void Enqueue(SQLOperation* op) - { - _queue->Push(op); - } + void Enqueue(SQLOperation* op); //! Gets a free connection in the synchronous connection pool. //! Caller MUST call t->Unlock() after touching the MySQL context to prevent deadlocks. T* GetFreeConnection(); - char const* GetDatabaseName() const - { - return _connectionInfo->database.c_str(); - } + char const* GetDatabaseName() const; //! Queue shared by async worker threads. std::unique_ptr<ProducerConsumerQueue<SQLOperation*>> _queue; diff --git a/src/server/database/Database/Field.cpp b/src/server/database/Database/Field.cpp index 29326287e63..0f3b3de548d 100644 --- a/src/server/database/Database/Field.cpp +++ b/src/server/database/Database/Field.cpp @@ -16,11 +16,12 @@ */ #include "Field.h" +#include "Log.h" Field::Field() { data.value = NULL; - data.type = MYSQL_TYPE_NULL; + data.type = DatabaseFieldTypes::Null; data.length = 0; data.raw = false; } @@ -30,7 +31,236 @@ Field::~Field() CleanUp(); } -void Field::SetByteValue(void* newValue, enum_field_types newType, uint32 length) +uint8 Field::GetUInt8() const +{ + if (!data.value) + return 0; + +#ifdef TRINITY_DEBUG + if (!IsType(DatabaseFieldTypes::Int8)) + { + TC_LOG_WARN("sql.sql", "Warning: GetUInt8() on non-tinyint field %s.%s (%s.%s) at index %u. Using type: %s.", + meta.TableAlias, meta.Alias, meta.TableName, meta.Name, meta.Index, meta.Type); + return 0; + } +#endif + + if (data.raw) + return *reinterpret_cast<uint8*>(data.value); + return static_cast<uint8>(strtoul((char*)data.value, nullptr, 10)); +} + +int8 Field::GetInt8() const +{ + if (!data.value) + return 0; + +#ifdef TRINITY_DEBUG + if (!IsType(DatabaseFieldTypes::Int8)) + { + TC_LOG_WARN("sql.sql", "Warning: GetInt8() on non-tinyint field %s.%s (%s.%s) at index %u. Using type: %s.", + meta.TableAlias, meta.Alias, meta.TableName, meta.Name, meta.Index, meta.Type); + return 0; + } +#endif + + if (data.raw) + return *reinterpret_cast<int8*>(data.value); + return static_cast<int8>(strtol((char*)data.value, NULL, 10)); +} + +uint16 Field::GetUInt16() const +{ + if (!data.value) + return 0; + +#ifdef TRINITY_DEBUG + if (!IsType(DatabaseFieldTypes::Int16)) + { + TC_LOG_WARN("sql.sql", "Warning: GetUInt16() on non-smallint field %s.%s (%s.%s) at index %u. Using type: %s.", + meta.TableAlias, meta.Alias, meta.TableName, meta.Name, meta.Index, meta.Type); + return 0; + } +#endif + + if (data.raw) + return *reinterpret_cast<uint16*>(data.value); + return static_cast<uint16>(strtoul((char*)data.value, nullptr, 10)); +} + +int16 Field::GetInt16() const +{ + if (!data.value) + return 0; + +#ifdef TRINITY_DEBUG + if (!IsType(DatabaseFieldTypes::Int16)) + { + TC_LOG_WARN("sql.sql", "Warning: GetInt16() on non-smallint field %s.%s (%s.%s) at index %u. Using type: %s.", + meta.TableAlias, meta.Alias, meta.TableName, meta.Name, meta.Index, meta.Type); + return 0; + } +#endif + + if (data.raw) + return *reinterpret_cast<int16*>(data.value); + return static_cast<int16>(strtol((char*)data.value, NULL, 10)); +} + +uint32 Field::GetUInt32() const +{ + if (!data.value) + return 0; + +#ifdef TRINITY_DEBUG + if (!IsType(DatabaseFieldTypes::Int32)) + { + TC_LOG_WARN("sql.sql", "Warning: GetUInt32() on non-(medium)int field %s.%s (%s.%s) at index %u. Using type: %s.", + meta.TableAlias, meta.Alias, meta.TableName, meta.Name, meta.Index, meta.Type); + return 0; + } +#endif + + if (data.raw) + return *reinterpret_cast<uint32*>(data.value); + return static_cast<uint32>(strtoul((char*)data.value, nullptr, 10)); +} + +int32 Field::GetInt32() const +{ + if (!data.value) + return 0; + +#ifdef TRINITY_DEBUG + if (!IsType(DatabaseFieldTypes::Int32)) + { + TC_LOG_WARN("sql.sql", "Warning: GetInt32() on non-(medium)int field %s.%s (%s.%s) at index %u. Using type: %s.", + meta.TableAlias, meta.Alias, meta.TableName, meta.Name, meta.Index, meta.Type); + return 0; + } +#endif + + if (data.raw) + return *reinterpret_cast<int32*>(data.value); + return static_cast<int32>(strtol((char*)data.value, NULL, 10)); +} + +uint64 Field::GetUInt64() const +{ + if (!data.value) + return 0; + +#ifdef TRINITY_DEBUG + if (!IsType(DatabaseFieldTypes::Int64)) + { + TC_LOG_WARN("sql.sql", "Warning: GetUInt64() on non-bigint field %s.%s (%s.%s) at index %u. Using type: %s.", + meta.TableAlias, meta.Alias, meta.TableName, meta.Name, meta.Index, meta.Type); + return 0; + } +#endif + + if (data.raw) + return *reinterpret_cast<uint64*>(data.value); + return static_cast<uint64>(strtoull((char*)data.value, nullptr, 10)); +} + +int64 Field::GetInt64() const +{ + if (!data.value) + return 0; + +#ifdef TRINITY_DEBUG + if (!IsType(DatabaseFieldTypes::Int64)) + { + TC_LOG_WARN("sql.sql", "Warning: GetInt64() on non-bigint field %s.%s (%s.%s) at index %u. Using type: %s.", + meta.TableAlias, meta.Alias, meta.TableName, meta.Name, meta.Index, meta.Type); + return 0; + } +#endif + + if (data.raw) + return *reinterpret_cast<int64*>(data.value); + return static_cast<int64>(strtoll((char*)data.value, NULL, 10)); +} + +float Field::GetFloat() const +{ + if (!data.value) + return 0.0f; + +#ifdef TRINITY_DEBUG + if (!IsType(DatabaseFieldTypes::Float)) + { + TC_LOG_WARN("sql.sql", "Warning: GetFloat() on non-float field %s.%s (%s.%s) at index %u. Using type: %s.", + meta.TableAlias, meta.Alias, meta.TableName, meta.Name, meta.Index, meta.Type); + return 0.0f; + } +#endif + + if (data.raw) + return *reinterpret_cast<float*>(data.value); + return static_cast<float>(atof((char*)data.value)); +} + +double Field::GetDouble() const +{ + if (!data.value) + return 0.0f; + +#ifdef TRINITY_DEBUG + if (!IsType(DatabaseFieldTypes::Double) && !IsType(DatabaseFieldTypes::Decimal)) + { + TC_LOG_WARN("sql.sql", "Warning: GetDouble() on non-double/non-decimal field %s.%s (%s.%s) at index %u. Using type: %s.", + meta.TableAlias, meta.Alias, meta.TableName, meta.Name, meta.Index, meta.Type); + return 0.0f; + } +#endif + + if (data.raw && !IsType(DatabaseFieldTypes::Decimal)) + return *reinterpret_cast<double*>(data.value); + return static_cast<double>(atof((char*)data.value)); +} + +char const* Field::GetCString() const +{ + if (!data.value) + return NULL; + +#ifdef TRINITY_DEBUG + if (IsNumeric() && data.raw) + { + TC_LOG_WARN("sql.sql", "Error: GetCString() on numeric field %s.%s (%s.%s) at index %u. Using type: %s.", + meta.TableAlias, meta.Alias, meta.TableName, meta.Name, meta.Index, meta.Type); + return NULL; + } +#endif + return static_cast<char const*>(data.value); +} + +std::string Field::GetString() const +{ + if (!data.value) + return ""; + + char const* string = GetCString(); + if (!string) + return ""; + + return std::string(string, data.length); +} + +std::vector<uint8> Field::GetBinary() const +{ + std::vector<uint8> result; + if (!data.value || !data.length) + return result; + + result.resize(data.length); + memcpy(result.data(), data.value, data.length); + return result; +} + +void Field::SetByteValue(void* newValue, DatabaseFieldTypes newType, uint32 length) { // This value stores raw bytes that have to be explicitly cast later data.value = newValue; @@ -39,7 +269,7 @@ void Field::SetByteValue(void* newValue, enum_field_types newType, uint32 length data.raw = true; } -void Field::SetStructuredValue(char* newValue, enum_field_types newType, uint32 length) +void Field::SetStructuredValue(char* newValue, DatabaseFieldTypes newType, uint32 length) { if (data.value) CleanUp(); @@ -56,3 +286,67 @@ void Field::SetStructuredValue(char* newValue, enum_field_types newType, uint32 data.type = newType; data.raw = false; } + +bool Field::IsType(DatabaseFieldTypes type) const +{ + return data.type == type; +} + +bool Field::IsNumeric() const +{ + return (data.type == DatabaseFieldTypes::Int8 || + data.type == DatabaseFieldTypes::Int16 || + data.type == DatabaseFieldTypes::Int32 || + data.type == DatabaseFieldTypes::Int64 || + data.type == DatabaseFieldTypes::Float || + data.type == DatabaseFieldTypes::Double); +} + +#ifdef TRINITY_DEBUG + +#include <mysql.h> + +static char const* FieldTypeToString(enum_field_types type) +{ + switch (type) + { + case MYSQL_TYPE_BIT: return "BIT"; + case MYSQL_TYPE_BLOB: return "BLOB"; + case MYSQL_TYPE_DATE: return "DATE"; + case MYSQL_TYPE_DATETIME: return "DATETIME"; + case MYSQL_TYPE_NEWDECIMAL: return "NEWDECIMAL"; + case MYSQL_TYPE_DECIMAL: return "DECIMAL"; + case MYSQL_TYPE_DOUBLE: return "DOUBLE"; + case MYSQL_TYPE_ENUM: return "ENUM"; + case MYSQL_TYPE_FLOAT: return "FLOAT"; + case MYSQL_TYPE_GEOMETRY: return "GEOMETRY"; + case MYSQL_TYPE_INT24: return "INT24"; + case MYSQL_TYPE_LONG: return "LONG"; + case MYSQL_TYPE_LONGLONG: return "LONGLONG"; + case MYSQL_TYPE_LONG_BLOB: return "LONG_BLOB"; + case MYSQL_TYPE_MEDIUM_BLOB: return "MEDIUM_BLOB"; + case MYSQL_TYPE_NEWDATE: return "NEWDATE"; + case MYSQL_TYPE_NULL: return "NULL"; + case MYSQL_TYPE_SET: return "SET"; + case MYSQL_TYPE_SHORT: return "SHORT"; + case MYSQL_TYPE_STRING: return "STRING"; + case MYSQL_TYPE_TIME: return "TIME"; + case MYSQL_TYPE_TIMESTAMP: return "TIMESTAMP"; + case MYSQL_TYPE_TINY: return "TINY"; + case MYSQL_TYPE_TINY_BLOB: return "TINY_BLOB"; + case MYSQL_TYPE_VAR_STRING: return "VAR_STRING"; + case MYSQL_TYPE_YEAR: return "YEAR"; + default: return "-Unknown-"; + } +} + +void Field::SetMetadata(MYSQL_FIELD* field, uint32 fieldIndex) +{ + meta.TableName = field->org_table; + meta.TableAlias = field->table; + meta.Name = field->org_name; + meta.Alias = field->name; + meta.Type = FieldTypeToString(field->type); + meta.Index = fieldIndex; +} +#endif diff --git a/src/server/database/Database/Field.h b/src/server/database/Database/Field.h index 8035dd16869..18cba2acd82 100644 --- a/src/server/database/Database/Field.h +++ b/src/server/database/Database/Field.h @@ -18,13 +18,23 @@ #ifndef _FIELD_H #define _FIELD_H -#include "Common.h" -#include "Log.h" +#include "Define.h" +#include "DatabaseEnvFwd.h" +#include <vector> -#ifdef _WIN32 -#include <winsock2.h> -#endif -#include <mysql.h> +enum class DatabaseFieldTypes : uint8 +{ + Null, + Int8, + Int16, + Int32, + Int64, + Float, + Double, + Decimal, + Date, + Binary +}; /** @class Field @@ -70,234 +80,19 @@ class TC_DATABASE_API Field return GetUInt8() == 1 ? true : false; } - uint8 GetUInt8() const - { - if (!data.value) - return 0; - - #ifdef TRINITY_DEBUG - if (!IsType(MYSQL_TYPE_TINY)) - { - TC_LOG_WARN("sql.sql", "Warning: GetUInt8() on non-tinyint field %s.%s (%s.%s) at index %u. Using type: %s.", - meta.TableAlias, meta.Alias, meta.TableName, meta.Name, meta.Index, meta.Type); - return 0; - } - #endif - - if (data.raw) - return *reinterpret_cast<uint8*>(data.value); - return static_cast<uint8>(strtoul((char*)data.value, nullptr, 10)); - } - - int8 GetInt8() const - { - if (!data.value) - return 0; - - #ifdef TRINITY_DEBUG - if (!IsType(MYSQL_TYPE_TINY)) - { - TC_LOG_WARN("sql.sql", "Warning: GetInt8() on non-tinyint field %s.%s (%s.%s) at index %u. Using type: %s.", - meta.TableAlias, meta.Alias, meta.TableName, meta.Name, meta.Index, meta.Type); - return 0; - } - #endif - - if (data.raw) - return *reinterpret_cast<int8*>(data.value); - return static_cast<int8>(strtol((char*)data.value, NULL, 10)); - } - - uint16 GetUInt16() const - { - if (!data.value) - return 0; - - #ifdef TRINITY_DEBUG - if (!IsType(MYSQL_TYPE_SHORT) && !IsType(MYSQL_TYPE_YEAR)) - { - TC_LOG_WARN("sql.sql", "Warning: GetUInt16() on non-smallint field %s.%s (%s.%s) at index %u. Using type: %s.", - meta.TableAlias, meta.Alias, meta.TableName, meta.Name, meta.Index, meta.Type); - return 0; - } - #endif - - if (data.raw) - return *reinterpret_cast<uint16*>(data.value); - return static_cast<uint16>(strtoul((char*)data.value, nullptr, 10)); - } - - int16 GetInt16() const - { - if (!data.value) - return 0; - - #ifdef TRINITY_DEBUG - if (!IsType(MYSQL_TYPE_SHORT) && !IsType(MYSQL_TYPE_YEAR)) - { - TC_LOG_WARN("sql.sql", "Warning: GetInt16() on non-smallint field %s.%s (%s.%s) at index %u. Using type: %s.", - meta.TableAlias, meta.Alias, meta.TableName, meta.Name, meta.Index, meta.Type); - return 0; - } - #endif - - if (data.raw) - return *reinterpret_cast<int16*>(data.value); - return static_cast<int16>(strtol((char*)data.value, NULL, 10)); - } - - uint32 GetUInt32() const - { - if (!data.value) - return 0; - - #ifdef TRINITY_DEBUG - if (!IsType(MYSQL_TYPE_INT24) && !IsType(MYSQL_TYPE_LONG)) - { - TC_LOG_WARN("sql.sql", "Warning: GetUInt32() on non-(medium)int field %s.%s (%s.%s) at index %u. Using type: %s.", - meta.TableAlias, meta.Alias, meta.TableName, meta.Name, meta.Index, meta.Type); - return 0; - } - #endif - - if (data.raw) - return *reinterpret_cast<uint32*>(data.value); - return static_cast<uint32>(strtoul((char*)data.value, nullptr, 10)); - } - - int32 GetInt32() const - { - if (!data.value) - return 0; - - #ifdef TRINITY_DEBUG - if (!IsType(MYSQL_TYPE_INT24) && !IsType(MYSQL_TYPE_LONG)) - { - TC_LOG_WARN("sql.sql", "Warning: GetInt32() on non-(medium)int field %s.%s (%s.%s) at index %u. Using type: %s.", - meta.TableAlias, meta.Alias, meta.TableName, meta.Name, meta.Index, meta.Type); - return 0; - } - #endif - - if (data.raw) - return *reinterpret_cast<int32*>(data.value); - return static_cast<int32>(strtol((char*)data.value, NULL, 10)); - } - - uint64 GetUInt64() const - { - if (!data.value) - return 0; - - #ifdef TRINITY_DEBUG - if (!IsType(MYSQL_TYPE_LONGLONG) && !IsType(MYSQL_TYPE_BIT)) - { - TC_LOG_WARN("sql.sql", "Warning: GetUInt64() on non-bigint field %s.%s (%s.%s) at index %u. Using type: %s.", - meta.TableAlias, meta.Alias, meta.TableName, meta.Name, meta.Index, meta.Type); - return 0; - } - #endif - - if (data.raw) - return *reinterpret_cast<uint64*>(data.value); - return static_cast<uint64>(strtoull((char*)data.value, nullptr, 10)); - } - - int64 GetInt64() const - { - if (!data.value) - return 0; - - #ifdef TRINITY_DEBUG - if (!IsType(MYSQL_TYPE_LONGLONG) && !IsType(MYSQL_TYPE_BIT)) - { - TC_LOG_WARN("sql.sql", "Warning: GetInt64() on non-bigint field %s.%s (%s.%s) at index %u. Using type: %s.", - meta.TableAlias, meta.Alias, meta.TableName, meta.Name, meta.Index, meta.Type); - return 0; - } - #endif - - if (data.raw) - return *reinterpret_cast<int64*>(data.value); - return static_cast<int64>(strtoll((char*)data.value, NULL, 10)); - } - - float GetFloat() const - { - if (!data.value) - return 0.0f; - - #ifdef TRINITY_DEBUG - if (!IsType(MYSQL_TYPE_FLOAT)) - { - TC_LOG_WARN("sql.sql", "Warning: GetFloat() on non-float field %s.%s (%s.%s) at index %u. Using type: %s.", - meta.TableAlias, meta.Alias, meta.TableName, meta.Name, meta.Index, meta.Type); - return 0.0f; - } - #endif - - if (data.raw) - return *reinterpret_cast<float*>(data.value); - return static_cast<float>(atof((char*)data.value)); - } - - double GetDouble() const - { - if (!data.value) - return 0.0f; - - #ifdef TRINITY_DEBUG - if (!IsType(MYSQL_TYPE_DOUBLE) && !IsType(MYSQL_TYPE_NEWDECIMAL)) - { - TC_LOG_WARN("sql.sql", "Warning: GetDouble() on non-double/non-decimal field %s.%s (%s.%s) at index %u. Using type: %s.", - meta.TableAlias, meta.Alias, meta.TableName, meta.Name, meta.Index, meta.Type); - return 0.0f; - } - #endif - - if (data.raw && !IsType(MYSQL_TYPE_NEWDECIMAL)) - return *reinterpret_cast<double*>(data.value); - return static_cast<double>(atof((char*)data.value)); - } - - char const* GetCString() const - { - if (!data.value) - return NULL; - - #ifdef TRINITY_DEBUG - if (IsNumeric()) - { - TC_LOG_WARN("sql.sql", "Error: GetCString() on numeric field %s.%s (%s.%s) at index %u. Using type: %s.", - meta.TableAlias, meta.Alias, meta.TableName, meta.Name, meta.Index, meta.Type); - return NULL; - } - #endif - return static_cast<char const*>(data.value); - } - - std::string GetString() const - { - if (!data.value) - return ""; - - char const* string = GetCString(); - if (!string) - return ""; - - return std::string(string, data.length); - } - - std::vector<uint8> GetBinary() const - { - std::vector<uint8> result; - if (!data.value || !data.length) - return result; - - result.resize(data.length); - memcpy(result.data(), data.value, data.length); - return result; - } + uint8 GetUInt8() const; + int8 GetInt8() const; + uint16 GetUInt16() const; + int16 GetInt16() const; + uint32 GetUInt32() const; + int32 GetInt32() const; + uint64 GetUInt64() const; + int64 GetInt64() const; + float GetFloat() const; + double GetDouble() const; + char const* GetCString() const; + std::string GetString() const; + std::vector<uint8> GetBinary() const; bool IsNull() const { @@ -320,13 +115,13 @@ class TC_DATABASE_API Field { uint32 length; // Length (prepared strings only) void* value; // Actual data in memory - enum_field_types type; // Field type + DatabaseFieldTypes type; // Field type bool raw; // Raw bytes? (Prepared statement or ad hoc) } data; #pragma pack(pop) - void SetByteValue(void* newValue, enum_field_types newType, uint32 length); - void SetStructuredValue(char* newValue, enum_field_types newType, uint32 length); + void SetByteValue(void* newValue, DatabaseFieldTypes newType, uint32 length); + void SetStructuredValue(char* newValue, DatabaseFieldTypes newType, uint32 length); void CleanUp() { @@ -336,120 +131,14 @@ class TC_DATABASE_API Field data.value = NULL; } - static uint32 SizeForType(MYSQL_FIELD* field) - { - switch (field->type) - { - case MYSQL_TYPE_NULL: - return 0; - case MYSQL_TYPE_TINY: - return 1; - case MYSQL_TYPE_YEAR: - case MYSQL_TYPE_SHORT: - return 2; - case MYSQL_TYPE_INT24: - case MYSQL_TYPE_LONG: - case MYSQL_TYPE_FLOAT: - return 4; - case MYSQL_TYPE_DOUBLE: - case MYSQL_TYPE_LONGLONG: - case MYSQL_TYPE_BIT: - return 8; - - case MYSQL_TYPE_TIMESTAMP: - case MYSQL_TYPE_DATE: - case MYSQL_TYPE_TIME: - case MYSQL_TYPE_DATETIME: - return sizeof(MYSQL_TIME); - - case MYSQL_TYPE_TINY_BLOB: - case MYSQL_TYPE_MEDIUM_BLOB: - case MYSQL_TYPE_LONG_BLOB: - case MYSQL_TYPE_BLOB: - case MYSQL_TYPE_STRING: - case MYSQL_TYPE_VAR_STRING: - return field->max_length + 1; - - case MYSQL_TYPE_DECIMAL: - case MYSQL_TYPE_NEWDECIMAL: - return 64; - - case MYSQL_TYPE_GEOMETRY: - /* - Following types are not sent over the wire: - MYSQL_TYPE_ENUM: - MYSQL_TYPE_SET: - */ - default: - TC_LOG_WARN("sql.sql", "SQL::SizeForType(): invalid field type %u", uint32(field->type)); - return 0; - } - } - - bool IsType(enum_field_types type) const - { - return data.type == type; - } + bool IsType(DatabaseFieldTypes type) const; - bool IsNumeric() const - { - return (data.type == MYSQL_TYPE_TINY || - data.type == MYSQL_TYPE_SHORT || - data.type == MYSQL_TYPE_INT24 || - data.type == MYSQL_TYPE_LONG || - data.type == MYSQL_TYPE_FLOAT || - data.type == MYSQL_TYPE_DOUBLE || - data.type == MYSQL_TYPE_LONGLONG ); - } + bool IsNumeric() const; private: #ifdef TRINITY_DEBUG - static char const* FieldTypeToString(enum_field_types type) - { - switch (type) - { - case MYSQL_TYPE_BIT: return "BIT"; - case MYSQL_TYPE_BLOB: return "BLOB"; - case MYSQL_TYPE_DATE: return "DATE"; - case MYSQL_TYPE_DATETIME: return "DATETIME"; - case MYSQL_TYPE_NEWDECIMAL: return "NEWDECIMAL"; - case MYSQL_TYPE_DECIMAL: return "DECIMAL"; - case MYSQL_TYPE_DOUBLE: return "DOUBLE"; - case MYSQL_TYPE_ENUM: return "ENUM"; - case MYSQL_TYPE_FLOAT: return "FLOAT"; - case MYSQL_TYPE_GEOMETRY: return "GEOMETRY"; - case MYSQL_TYPE_INT24: return "INT24"; - case MYSQL_TYPE_LONG: return "LONG"; - case MYSQL_TYPE_LONGLONG: return "LONGLONG"; - case MYSQL_TYPE_LONG_BLOB: return "LONG_BLOB"; - case MYSQL_TYPE_MEDIUM_BLOB: return "MEDIUM_BLOB"; - case MYSQL_TYPE_NEWDATE: return "NEWDATE"; - case MYSQL_TYPE_NULL: return "NULL"; - case MYSQL_TYPE_SET: return "SET"; - case MYSQL_TYPE_SHORT: return "SHORT"; - case MYSQL_TYPE_STRING: return "STRING"; - case MYSQL_TYPE_TIME: return "TIME"; - case MYSQL_TYPE_TIMESTAMP: return "TIMESTAMP"; - case MYSQL_TYPE_TINY: return "TINY"; - case MYSQL_TYPE_TINY_BLOB: return "TINY_BLOB"; - case MYSQL_TYPE_VAR_STRING: return "VAR_STRING"; - case MYSQL_TYPE_YEAR: return "YEAR"; - default: return "-Unknown-"; - } - } - - void SetMetadata(MYSQL_FIELD* field, uint32 fieldIndex) - { - meta.TableName = field->org_table; - meta.TableAlias = field->table; - meta.Name = field->org_name; - meta.Alias = field->name; - meta.Type = FieldTypeToString(field->type); - meta.Index = fieldIndex; - } - + void SetMetadata(MYSQL_FIELD* field, uint32 fieldIndex); Metadata meta; - #endif }; diff --git a/src/server/database/Database/Implementation/CharacterDatabase.cpp b/src/server/database/Database/Implementation/CharacterDatabase.cpp index 5d5255f82f3..99f3a487829 100644 --- a/src/server/database/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/database/Database/Implementation/CharacterDatabase.cpp @@ -16,6 +16,7 @@ */ #include "CharacterDatabase.h" +#include "PreparedStatement.h" void CharacterDatabaseConnection::DoPrepareStatements() { @@ -735,3 +736,15 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_INS_SCENARIO_INSTANCE_CRITERIA, "INSERT INTO instance_scenario_progress (id, criteria, counter, date) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_SCENARIO_INSTANCE_CRITERIA_FOR_INSTANCE, "DELETE FROM instance_scenario_progress WHERE id = ?", CONNECTION_ASYNC); } + +CharacterDatabaseConnection::CharacterDatabaseConnection(MySQLConnectionInfo& connInfo) : MySQLConnection(connInfo) +{ +} + +CharacterDatabaseConnection::CharacterDatabaseConnection(ProducerConsumerQueue<SQLOperation*>* q, MySQLConnectionInfo& connInfo) : MySQLConnection(q, connInfo) +{ +} + +CharacterDatabaseConnection::~CharacterDatabaseConnection() +{ +} diff --git a/src/server/database/Database/Implementation/CharacterDatabase.h b/src/server/database/Database/Implementation/CharacterDatabase.h index 97190f9f614..c2ea5136261 100644 --- a/src/server/database/Database/Implementation/CharacterDatabase.h +++ b/src/server/database/Database/Implementation/CharacterDatabase.h @@ -18,10 +18,9 @@ #ifndef _CHARACTERDATABASE_H #define _CHARACTERDATABASE_H -#include "DatabaseWorkerPool.h" #include "MySQLConnection.h" -enum CharacterDatabaseStatements +enum CharacterDatabaseStatements : uint32 { /* Naming standard for defines: {DB}_{SEL/INS/UPD/DEL/REP}_{Summary of data changed} @@ -633,13 +632,12 @@ public: typedef CharacterDatabaseStatements Statements; //- Constructors for sync and async connections - CharacterDatabaseConnection(MySQLConnectionInfo& connInfo) : MySQLConnection(connInfo) { } - CharacterDatabaseConnection(ProducerConsumerQueue<SQLOperation*>* q, MySQLConnectionInfo& connInfo) : MySQLConnection(q, connInfo) { } + CharacterDatabaseConnection(MySQLConnectionInfo& connInfo); + CharacterDatabaseConnection(ProducerConsumerQueue<SQLOperation*>* q, MySQLConnectionInfo& connInfo); + ~CharacterDatabaseConnection(); //- Loads database type specific prepared statements void DoPrepareStatements() override; }; -typedef DatabaseWorkerPool<CharacterDatabaseConnection> CharacterDatabaseWorkerPool; - #endif diff --git a/src/server/database/Database/Implementation/HotfixDatabase.cpp b/src/server/database/Database/Implementation/HotfixDatabase.cpp index 2758c76bf09..da134a3d9b0 100644 --- a/src/server/database/Database/Implementation/HotfixDatabase.cpp +++ b/src/server/database/Database/Implementation/HotfixDatabase.cpp @@ -19,6 +19,7 @@ // Autogenerated from DB2Structure.h #include "HotfixDatabase.h" +#include "PreparedStatement.h" // Force locale statments to appear exactly in locale declaration order, right after normal data fetch statement #define PREPARE_LOCALE_STMT(stmtBase, sql, con) \ @@ -978,3 +979,15 @@ void HotfixDatabaseConnection::DoPrepareStatements() PrepareStatement(HOTFIX_SEL_WORLD_SAFE_LOCS, "SELECT ID, LocX, LocY, LocZ, Facing, AreaName, MapID FROM world_safe_locs ORDER BY ID DESC", CONNECTION_SYNCH); PREPARE_LOCALE_STMT(HOTFIX_SEL_WORLD_SAFE_LOCS, "SELECT ID, AreaName_lang FROM world_safe_locs_locale WHERE locale = ?", CONNECTION_SYNCH); } + +HotfixDatabaseConnection::HotfixDatabaseConnection(MySQLConnectionInfo& connInfo) : MySQLConnection(connInfo) +{ +} + +HotfixDatabaseConnection::HotfixDatabaseConnection(ProducerConsumerQueue<SQLOperation*>* q, MySQLConnectionInfo& connInfo) : MySQLConnection(q, connInfo) +{ +} + +HotfixDatabaseConnection::~HotfixDatabaseConnection() +{ +} diff --git a/src/server/database/Database/Implementation/HotfixDatabase.h b/src/server/database/Database/Implementation/HotfixDatabase.h index 141f3ddc878..4e53630805f 100644 --- a/src/server/database/Database/Implementation/HotfixDatabase.h +++ b/src/server/database/Database/Implementation/HotfixDatabase.h @@ -21,10 +21,9 @@ #ifndef _HOTFIXDATABASE_H #define _HOTFIXDATABASE_H -#include "DatabaseWorkerPool.h" #include "MySQLConnection.h" -enum HotfixDatabaseStatements +enum HotfixDatabaseStatements : uint32 { /* Naming standard for defines: {DB}_{SEL/INS/UPD/DEL/REP}_{Summary of data changed} @@ -525,13 +524,12 @@ public: typedef HotfixDatabaseStatements Statements; //- Constructors for sync and async connections - HotfixDatabaseConnection(MySQLConnectionInfo& connInfo) : MySQLConnection(connInfo) { } - HotfixDatabaseConnection(ProducerConsumerQueue<SQLOperation*>* q, MySQLConnectionInfo& connInfo) : MySQLConnection(q, connInfo) { } + HotfixDatabaseConnection(MySQLConnectionInfo& connInfo); + HotfixDatabaseConnection(ProducerConsumerQueue<SQLOperation*>* q, MySQLConnectionInfo& connInfo); + ~HotfixDatabaseConnection(); //- Loads database type specific prepared statements void DoPrepareStatements() override; }; -typedef DatabaseWorkerPool<HotfixDatabaseConnection> HotfixDatabaseWorkerPool; - #endif diff --git a/src/server/database/Database/Implementation/LoginDatabase.cpp b/src/server/database/Database/Implementation/LoginDatabase.cpp index 414faafeff5..fe2d913538d 100644 --- a/src/server/database/Database/Implementation/LoginDatabase.cpp +++ b/src/server/database/Database/Implementation/LoginDatabase.cpp @@ -16,6 +16,7 @@ */ #include "LoginDatabase.h" +#include "PreparedStatement.h" void LoginDatabaseConnection::DoPrepareStatements() { @@ -176,3 +177,15 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_INS_BNET_ITEM_FAVORITE_APPEARANCE, "INSERT INTO battlenet_item_favorite_appearances (battlenetAccountId, itemModifiedAppearanceId) VALUES (?, ?)", CONNECTION_ASYNC); PrepareStatement(LOGIN_DEL_BNET_ITEM_FAVORITE_APPEARANCE, "DELETE FROM battlenet_item_favorite_appearances WHERE battlenetAccountId = ? AND itemModifiedAppearanceId = ?", CONNECTION_ASYNC); } + +LoginDatabaseConnection::LoginDatabaseConnection(MySQLConnectionInfo& connInfo) : MySQLConnection(connInfo) +{ +} + +LoginDatabaseConnection::LoginDatabaseConnection(ProducerConsumerQueue<SQLOperation*>* q, MySQLConnectionInfo& connInfo) : MySQLConnection(q, connInfo) +{ +} + +LoginDatabaseConnection::~LoginDatabaseConnection() +{ +} diff --git a/src/server/database/Database/Implementation/LoginDatabase.h b/src/server/database/Database/Implementation/LoginDatabase.h index d9eb9fc157c..b58630b4ae5 100644 --- a/src/server/database/Database/Implementation/LoginDatabase.h +++ b/src/server/database/Database/Implementation/LoginDatabase.h @@ -18,10 +18,9 @@ #ifndef _LOGINDATABASE_H #define _LOGINDATABASE_H -#include "DatabaseWorkerPool.h" #include "MySQLConnection.h" -enum LoginDatabaseStatements +enum LoginDatabaseStatements : uint32 { /* Naming standard for defines: {DB}_{SEL/INS/UPD/DEL/REP}_{Summary of data changed} @@ -171,13 +170,12 @@ public: typedef LoginDatabaseStatements Statements; //- Constructors for sync and async connections - LoginDatabaseConnection(MySQLConnectionInfo& connInfo) : MySQLConnection(connInfo) { } - LoginDatabaseConnection(ProducerConsumerQueue<SQLOperation*>* q, MySQLConnectionInfo& connInfo) : MySQLConnection(q, connInfo) { } + LoginDatabaseConnection(MySQLConnectionInfo& connInfo); + LoginDatabaseConnection(ProducerConsumerQueue<SQLOperation*>* q, MySQLConnectionInfo& connInfo); + ~LoginDatabaseConnection(); //- Loads database type specific prepared statements void DoPrepareStatements() override; }; -typedef DatabaseWorkerPool<LoginDatabaseConnection> LoginDatabaseWorkerPool; - #endif diff --git a/src/server/database/Database/Implementation/WorldDatabase.cpp b/src/server/database/Database/Implementation/WorldDatabase.cpp index def1e948a06..52a2ca918c1 100644 --- a/src/server/database/Database/Implementation/WorldDatabase.cpp +++ b/src/server/database/Database/Implementation/WorldDatabase.cpp @@ -16,6 +16,7 @@ */ #include "WorldDatabase.h" +#include "PreparedStatement.h" void WorldDatabaseConnection::DoPrepareStatements() { @@ -92,3 +93,15 @@ void WorldDatabaseConnection::DoPrepareStatements() PrepareStatement(WORLD_UPD_GAMEOBJECT_ZONE_AREA_DATA, "UPDATE gameobject SET zoneId = ?, areaId = ? WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(WORLD_SEL_GUILD_REWARDS_REQ_ACHIEVEMENTS, "SELECT AchievementRequired FROM guild_rewards_req_achievements WHERE ItemID = ?", CONNECTION_SYNCH); } + +WorldDatabaseConnection::WorldDatabaseConnection(MySQLConnectionInfo& connInfo) : MySQLConnection(connInfo) +{ +} + +WorldDatabaseConnection::WorldDatabaseConnection(ProducerConsumerQueue<SQLOperation*>* q, MySQLConnectionInfo& connInfo) : MySQLConnection(q, connInfo) +{ +} + +WorldDatabaseConnection::~WorldDatabaseConnection() +{ +} diff --git a/src/server/database/Database/Implementation/WorldDatabase.h b/src/server/database/Database/Implementation/WorldDatabase.h index e8f1f0c16fe..425919d3379 100644 --- a/src/server/database/Database/Implementation/WorldDatabase.h +++ b/src/server/database/Database/Implementation/WorldDatabase.h @@ -18,10 +18,9 @@ #ifndef _WORLDDATABASE_H #define _WORLDDATABASE_H -#include "DatabaseWorkerPool.h" #include "MySQLConnection.h" -enum WorldDatabaseStatements +enum WorldDatabaseStatements : uint32 { /* Naming standard for defines: {DB}_{SEL/INS/UPD/DEL/REP}_{Summary of data changed} @@ -109,13 +108,12 @@ public: typedef WorldDatabaseStatements Statements; //- Constructors for sync and async connections - WorldDatabaseConnection(MySQLConnectionInfo& connInfo) : MySQLConnection(connInfo) { } - WorldDatabaseConnection(ProducerConsumerQueue<SQLOperation*>* q, MySQLConnectionInfo& connInfo) : MySQLConnection(q, connInfo) { } + WorldDatabaseConnection(MySQLConnectionInfo& connInfo); + WorldDatabaseConnection(ProducerConsumerQueue<SQLOperation*>* q, MySQLConnectionInfo& connInfo); + ~WorldDatabaseConnection(); //- Loads database type specific prepared statements void DoPrepareStatements() override; }; -typedef DatabaseWorkerPool<WorldDatabaseConnection> WorldDatabaseWorkerPool; - #endif diff --git a/src/server/database/Database/MySQLConnection.cpp b/src/server/database/Database/MySQLConnection.cpp index 47ed4a97c3e..2598e3214ff 100644 --- a/src/server/database/Database/MySQLConnection.cpp +++ b/src/server/database/Database/MySQLConnection.cpp @@ -15,23 +15,34 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ - -#include "Common.h" - -#ifdef _WIN32 - #include <winsock2.h> -#endif -#include <mysql.h> -#include <errmsg.h> - #include "MySQLConnection.h" -#include "QueryResult.h" -#include "SQLOperation.h" -#include "PreparedStatement.h" +#include "Common.h" #include "DatabaseWorker.h" -#include "Timer.h" #include "Log.h" -#include "ProducerConsumerQueue.h" +#include "PreparedStatement.h" +#include "QueryResult.h" +#include "Timer.h" +#include "Transaction.h" +#include "Util.h" +#include <errmsg.h> +#include <mysql.h> +#include <mysqld_error.h> + +MySQLConnectionInfo::MySQLConnectionInfo(std::string const& infoString) +{ + Tokenizer tokens(infoString, ';'); + + if (tokens.size() != 5) + return; + + uint8 i = 0; + + host.assign(tokens[i++]); + port_or_socket.assign(tokens[i++]); + user.assign(tokens[i++]); + password.assign(tokens[i++]); + database.assign(tokens[i++]); +} MySQLConnection::MySQLConnection(MySQLConnectionInfo& connInfo) : m_reconnecting(false), @@ -360,14 +371,13 @@ void MySQLConnection::CommitTransaction() int MySQLConnection::ExecuteTransaction(SQLTransaction& transaction) { - std::list<SQLElementData> const& queries = transaction->m_queries; + std::vector<SQLElementData> const& queries = transaction->m_queries; if (queries.empty()) return -1; BeginTransaction(); - std::list<SQLElementData>::const_iterator itr; - for (itr = queries.begin(); itr != queries.end(); ++itr) + for (auto itr = queries.begin(); itr != queries.end(); ++itr) { SQLElementData const& data = *itr; switch (itr->type) @@ -410,6 +420,26 @@ int MySQLConnection::ExecuteTransaction(SQLTransaction& transaction) return 0; } +void MySQLConnection::Ping() +{ + mysql_ping(m_Mysql); +} + +uint32 MySQLConnection::GetLastError() +{ + return mysql_errno(m_Mysql); +} + +bool MySQLConnection::LockIfReady() +{ + return m_Mutex.try_lock(); +} + +void MySQLConnection::Unlock() +{ + m_Mutex.unlock(); +} + MySQLPreparedStatement* MySQLConnection::GetPreparedStatement(uint32 index) { ASSERT(index < m_stmts.size()); diff --git a/src/server/database/Database/MySQLConnection.h b/src/server/database/Database/MySQLConnection.h index 42fb976c729..3bc9aa603c7 100644 --- a/src/server/database/Database/MySQLConnection.h +++ b/src/server/database/Database/MySQLConnection.h @@ -15,19 +15,23 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "DatabaseWorkerPool.h" -#include "Transaction.h" -#include "Util.h" -#include "ProducerConsumerQueue.h" -#include <map> - #ifndef _MYSQLCONNECTION_H #define _MYSQLCONNECTION_H +#include "Define.h" +#include "DatabaseEnvFwd.h" +#include <map> +#include <memory> +#include <mutex> +#include <string> +#include <vector> + +template <typename T> +class ProducerConsumerQueue; + class DatabaseWorker; -class PreparedStatement; class MySQLPreparedStatement; -class PingOperation; +class SQLOperation; enum ConnectionFlags { @@ -38,21 +42,7 @@ enum ConnectionFlags struct TC_DATABASE_API MySQLConnectionInfo { - explicit MySQLConnectionInfo(std::string const& infoString) - { - Tokenizer tokens(infoString, ';'); - - if (tokens.size() != 5) - return; - - uint8 i = 0; - - host.assign(tokens[i++]); - port_or_socket.assign(tokens[i++]); - user.assign(tokens[i++]); - password.assign(tokens[i++]); - database.assign(tokens[i++]); - } + explicit MySQLConnectionInfo(std::string const& infoString); std::string user; std::string password; @@ -91,24 +81,17 @@ class TC_DATABASE_API MySQLConnection void CommitTransaction(); int ExecuteTransaction(SQLTransaction& transaction); - operator bool () const { return m_Mysql != NULL; } - void Ping() { mysql_ping(m_Mysql); } + void Ping(); - uint32 GetLastError() { return mysql_errno(m_Mysql); } + uint32 GetLastError(); protected: - bool LockIfReady() - { - /// Tries to acquire lock. If lock is acquired by another thread - /// the calling parent will just try another connection - return m_Mutex.try_lock(); - } - - void Unlock() - { - /// Called by parent databasepool. Will let other threads access this connection - m_Mutex.unlock(); - } + /// Tries to acquire lock. If lock is acquired by another thread + /// the calling parent will just try another connection + bool LockIfReady(); + + /// Called by parent databasepool. Will let other threads access this connection + void Unlock(); MYSQL* GetHandle() { return m_Mysql; } MySQLPreparedStatement* GetPreparedStatement(uint32 index); diff --git a/src/server/database/Database/MySQLThreading.cpp b/src/server/database/Database/MySQLThreading.cpp new file mode 100644 index 00000000000..d86f61853eb --- /dev/null +++ b/src/server/database/Database/MySQLThreading.cpp @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2008-2017 TrinityCore <http://www.trinitycore.org/> + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +#include "MySQLThreading.h" +#include <mysql.h> + +void MySQL::Library_Init() +{ + mysql_library_init(-1, NULL, NULL); +} + +void MySQL::Library_End() +{ + mysql_library_end(); +} diff --git a/src/server/database/Database/MySQLThreading.h b/src/server/database/Database/MySQLThreading.h index 68a8c3ea7ed..deef5561e6d 100644 --- a/src/server/database/Database/MySQLThreading.h +++ b/src/server/database/Database/MySQLThreading.h @@ -18,20 +18,12 @@ #ifndef _MYSQLTHREADING_H #define _MYSQLTHREADING_H -#include "Log.h" +#include "Define.h" -class TC_DATABASE_API MySQL +namespace MySQL { - public: - static void Library_Init() - { - mysql_library_init(-1, NULL, NULL); - } - - static void Library_End() - { - mysql_library_end(); - } + void TC_DATABASE_API Library_Init(); + void TC_DATABASE_API Library_End(); }; #endif diff --git a/src/server/database/Database/PreparedStatement.cpp b/src/server/database/Database/PreparedStatement.cpp index 6e00da4e33f..a756ddf6757 100644 --- a/src/server/database/Database/PreparedStatement.cpp +++ b/src/server/database/Database/PreparedStatement.cpp @@ -16,8 +16,12 @@ */ #include "PreparedStatement.h" +#include "Errors.h" #include "MySQLConnection.h" +#include "QueryResult.h" #include "Log.h" +#include <mysql.h> +#include <sstream> PreparedStatement::PreparedStatement(uint32 index) : m_stmt(NULL), @@ -27,7 +31,7 @@ PreparedStatement::~PreparedStatement() { } void PreparedStatement::BindParameters() { - ASSERT (m_stmt); + ASSERT(m_stmt); uint8 i = 0; for (; i < statement_data.size(); i++) @@ -257,14 +261,40 @@ static bool ParamenterIndexAssertFail(uint32 stmtIndex, uint8 index, uint32 para return false; } +static void SetParameterValue(MYSQL_BIND* param, enum_field_types type, const void* value, uint32 len, bool isUnsigned) +{ + param->buffer_type = type; + delete[] static_cast<char *>(param->buffer); + param->buffer = new char[len]; + param->buffer_length = 0; + param->is_null_value = 0; + param->length = NULL; // Only != NULL for strings + param->is_unsigned = isUnsigned; + + memcpy(param->buffer, value, len); +} + //- Bind on mysql level -bool MySQLPreparedStatement::CheckValidIndex(uint8 index) +void MySQLPreparedStatement::CheckValidIndex(uint8 index) { ASSERT(index < m_paramCount || ParamenterIndexAssertFail(m_stmt->m_index, index, m_paramCount)); if (m_paramsSet[index]) TC_LOG_WARN("sql.sql", "[WARNING] Prepared Statement (id: %u) trying to bind value on already bound index (%u).", m_stmt->m_index, index); - return true; +} + +void MySQLPreparedStatement::setNull(const uint8 index) +{ + CheckValidIndex(index); + m_paramsSet[index] = true; + MYSQL_BIND* param = &m_bind[index]; + param->buffer_type = MYSQL_TYPE_NULL; + delete[] static_cast<char *>(param->buffer); + param->buffer = NULL; + param->buffer_length = 0; + param->is_null_value = 1; + delete param->length; + param->length = NULL; } void MySQLPreparedStatement::setBool(const uint8 index, const bool value) @@ -277,7 +307,7 @@ void MySQLPreparedStatement::setUInt8(const uint8 index, const uint8 value) CheckValidIndex(index); m_paramsSet[index] = true; MYSQL_BIND* param = &m_bind[index]; - setValue(param, MYSQL_TYPE_TINY, &value, sizeof(uint8), true); + SetParameterValue(param, MYSQL_TYPE_TINY, &value, sizeof(uint8), true); } void MySQLPreparedStatement::setUInt16(const uint8 index, const uint16 value) @@ -285,7 +315,7 @@ void MySQLPreparedStatement::setUInt16(const uint8 index, const uint16 value) CheckValidIndex(index); m_paramsSet[index] = true; MYSQL_BIND* param = &m_bind[index]; - setValue(param, MYSQL_TYPE_SHORT, &value, sizeof(uint16), true); + SetParameterValue(param, MYSQL_TYPE_SHORT, &value, sizeof(uint16), true); } void MySQLPreparedStatement::setUInt32(const uint8 index, const uint32 value) @@ -293,7 +323,7 @@ void MySQLPreparedStatement::setUInt32(const uint8 index, const uint32 value) CheckValidIndex(index); m_paramsSet[index] = true; MYSQL_BIND* param = &m_bind[index]; - setValue(param, MYSQL_TYPE_LONG, &value, sizeof(uint32), true); + SetParameterValue(param, MYSQL_TYPE_LONG, &value, sizeof(uint32), true); } void MySQLPreparedStatement::setUInt64(const uint8 index, const uint64 value) @@ -301,7 +331,7 @@ void MySQLPreparedStatement::setUInt64(const uint8 index, const uint64 value) CheckValidIndex(index); m_paramsSet[index] = true; MYSQL_BIND* param = &m_bind[index]; - setValue(param, MYSQL_TYPE_LONGLONG, &value, sizeof(uint64), true); + SetParameterValue(param, MYSQL_TYPE_LONGLONG, &value, sizeof(uint64), true); } void MySQLPreparedStatement::setInt8(const uint8 index, const int8 value) @@ -309,7 +339,7 @@ void MySQLPreparedStatement::setInt8(const uint8 index, const int8 value) CheckValidIndex(index); m_paramsSet[index] = true; MYSQL_BIND* param = &m_bind[index]; - setValue(param, MYSQL_TYPE_TINY, &value, sizeof(int8), false); + SetParameterValue(param, MYSQL_TYPE_TINY, &value, sizeof(int8), false); } void MySQLPreparedStatement::setInt16(const uint8 index, const int16 value) @@ -317,7 +347,7 @@ void MySQLPreparedStatement::setInt16(const uint8 index, const int16 value) CheckValidIndex(index); m_paramsSet[index] = true; MYSQL_BIND* param = &m_bind[index]; - setValue(param, MYSQL_TYPE_SHORT, &value, sizeof(int16), false); + SetParameterValue(param, MYSQL_TYPE_SHORT, &value, sizeof(int16), false); } void MySQLPreparedStatement::setInt32(const uint8 index, const int32 value) @@ -325,7 +355,7 @@ void MySQLPreparedStatement::setInt32(const uint8 index, const int32 value) CheckValidIndex(index); m_paramsSet[index] = true; MYSQL_BIND* param = &m_bind[index]; - setValue(param, MYSQL_TYPE_LONG, &value, sizeof(int32), false); + SetParameterValue(param, MYSQL_TYPE_LONG, &value, sizeof(int32), false); } void MySQLPreparedStatement::setInt64(const uint8 index, const int64 value) @@ -333,7 +363,7 @@ void MySQLPreparedStatement::setInt64(const uint8 index, const int64 value) CheckValidIndex(index); m_paramsSet[index] = true; MYSQL_BIND* param = &m_bind[index]; - setValue(param, MYSQL_TYPE_LONGLONG, &value, sizeof(int64), false); + SetParameterValue(param, MYSQL_TYPE_LONGLONG, &value, sizeof(int64), false); } void MySQLPreparedStatement::setFloat(const uint8 index, const float value) @@ -341,7 +371,7 @@ void MySQLPreparedStatement::setFloat(const uint8 index, const float value) CheckValidIndex(index); m_paramsSet[index] = true; MYSQL_BIND* param = &m_bind[index]; - setValue(param, MYSQL_TYPE_FLOAT, &value, sizeof(float), (value > 0.0f)); + SetParameterValue(param, MYSQL_TYPE_FLOAT, &value, sizeof(float), (value > 0.0f)); } void MySQLPreparedStatement::setDouble(const uint8 index, const double value) @@ -349,7 +379,7 @@ void MySQLPreparedStatement::setDouble(const uint8 index, const double value) CheckValidIndex(index); m_paramsSet[index] = true; MYSQL_BIND* param = &m_bind[index]; - setValue(param, MYSQL_TYPE_DOUBLE, &value, sizeof(double), (value > 0.0f)); + SetParameterValue(param, MYSQL_TYPE_DOUBLE, &value, sizeof(double), (value > 0.0f)); } void MySQLPreparedStatement::setBinary(const uint8 index, const std::vector<uint8>& value, bool isString) @@ -374,33 +404,6 @@ void MySQLPreparedStatement::setBinary(const uint8 index, const std::vector<uint memcpy(param->buffer, value.data(), len); } -void MySQLPreparedStatement::setNull(const uint8 index) -{ - CheckValidIndex(index); - m_paramsSet[index] = true; - MYSQL_BIND* param = &m_bind[index]; - param->buffer_type = MYSQL_TYPE_NULL; - delete [] static_cast<char *>(param->buffer); - param->buffer = NULL; - param->buffer_length = 0; - param->is_null_value = 1; - delete param->length; - param->length = NULL; -} - -void MySQLPreparedStatement::setValue(MYSQL_BIND* param, enum_field_types type, const void* value, uint32 len, bool isUnsigned) -{ - param->buffer_type = type; - delete [] static_cast<char *>(param->buffer); - param->buffer = new char[len]; - param->buffer_length = 0; - param->is_null_value = 0; - param->length = NULL; // Only != NULL for strings - param->is_unsigned = isUnsigned; - - memcpy(param->buffer, value, len); -} - std::string MySQLPreparedStatement::getQueryString(std::string const& sqlPattern) const { std::string queryString = sqlPattern; diff --git a/src/server/database/Database/PreparedStatement.h b/src/server/database/Database/PreparedStatement.h index ddc731625fa..7e39581e4d3 100644 --- a/src/server/database/Database/PreparedStatement.h +++ b/src/server/database/Database/PreparedStatement.h @@ -18,8 +18,10 @@ #ifndef _PREPAREDSTATEMENT_H #define _PREPAREDSTATEMENT_H -#include <future> +#include "Define.h" #include "SQLOperation.h" +#include <future> +#include <vector> #ifdef __APPLE__ #undef TYPE_BOOL @@ -120,6 +122,7 @@ class TC_DATABASE_API MySQLPreparedStatement MySQLPreparedStatement(MYSQL_STMT* stmt); ~MySQLPreparedStatement(); + void setNull(const uint8 index); void setBool(const uint8 index, const bool value); void setUInt8(const uint8 index, const uint8 value); void setUInt16(const uint8 index, const uint16 value); @@ -132,20 +135,16 @@ class TC_DATABASE_API MySQLPreparedStatement void setFloat(const uint8 index, const float value); void setDouble(const uint8 index, const double value); void setBinary(const uint8 index, const std::vector<uint8>& value, bool isString); - void setNull(const uint8 index); protected: MYSQL_STMT* GetSTMT() { return m_Mstmt; } MYSQL_BIND* GetBind() { return m_bind; } PreparedStatement* m_stmt; void ClearParameters(); - bool CheckValidIndex(uint8 index); + void CheckValidIndex(uint8 index); std::string getQueryString(std::string const& sqlPattern) const; private: - void setValue(MYSQL_BIND* param, enum_field_types type, const void* value, uint32 len, bool isUnsigned); - - private: MYSQL_STMT* m_Mstmt; uint32 m_paramCount; std::vector<bool> m_paramsSet; @@ -155,9 +154,6 @@ class TC_DATABASE_API MySQLPreparedStatement MySQLPreparedStatement& operator=(MySQLPreparedStatement const& right) = delete; }; -typedef std::future<PreparedQueryResult> PreparedQueryResultFuture; -typedef std::promise<PreparedQueryResult> PreparedQueryResultPromise; - //- Lower-level class, enqueuable operation class TC_DATABASE_API PreparedStatementTask : public SQLOperation { diff --git a/src/server/database/Database/QueryCallback.cpp b/src/server/database/Database/QueryCallback.cpp index 2d89e08a956..18f72975935 100644 --- a/src/server/database/Database/QueryCallback.cpp +++ b/src/server/database/Database/QueryCallback.cpp @@ -16,6 +16,7 @@ */ #include "QueryCallback.h" +#include "Errors.h" template<typename T, typename... Args> inline void Construct(T& t, Args&&... args) @@ -30,7 +31,7 @@ inline void Destroy(T& t) } template<typename T> -void ConstructActiveMember(T* obj) +inline void ConstructActiveMember(T* obj) { if (!obj->_isPrepared) Construct(obj->_string); @@ -39,7 +40,7 @@ void ConstructActiveMember(T* obj) } template<typename T> -void DestroyActiveMember(T* obj) +inline void DestroyActiveMember(T* obj) { if (!obj->_isPrepared) Destroy(obj->_string); @@ -48,7 +49,7 @@ void DestroyActiveMember(T* obj) } template<typename T> -void MoveFrom(T* to, T&& from) +inline void MoveFrom(T* to, T&& from) { ASSERT(to->_isPrepared == from._isPrepared); @@ -199,7 +200,7 @@ QueryCallback::Status QueryCallback::InvokeIfReady() { if (_string.valid() && _string.wait_for(std::chrono::seconds(0)) == std::future_status::ready) { - std::future<QueryResult> f(std::move(_string)); + QueryResultFuture f(std::move(_string)); std::function<void(QueryCallback&, QueryResult)> cb(std::move(callback._string)); cb(*this, f.get()); return checkStateAndReturnCompletion(); @@ -209,7 +210,7 @@ QueryCallback::Status QueryCallback::InvokeIfReady() { if (_prepared.valid() && _prepared.wait_for(std::chrono::seconds(0)) == std::future_status::ready) { - std::future<PreparedQueryResult> f(std::move(_prepared)); + PreparedQueryResultFuture f(std::move(_prepared)); std::function<void(QueryCallback&, PreparedQueryResult)> cb(std::move(callback._prepared)); cb(*this, f.get()); return checkStateAndReturnCompletion(); diff --git a/src/server/database/Database/QueryCallback.h b/src/server/database/Database/QueryCallback.h index 8258da37afb..ebc1538b5e9 100644 --- a/src/server/database/Database/QueryCallback.h +++ b/src/server/database/Database/QueryCallback.h @@ -18,16 +18,19 @@ #ifndef _QUERY_CALLBACK_H #define _QUERY_CALLBACK_H -#include "QueryResult.h" +#include "Define.h" +#include "DatabaseEnvFwd.h" +#include <functional> #include <future> #include <list> #include <queue> +#include <utility> class TC_DATABASE_API QueryCallback { public: - explicit QueryCallback(std::future<QueryResult>&& result); - explicit QueryCallback(std::future<PreparedQueryResult>&& result); + explicit QueryCallback(QueryResultFuture&& result); + explicit QueryCallback(PreparedQueryResultFuture&& result); QueryCallback(QueryCallback&& right); QueryCallback& operator=(QueryCallback&& right); ~QueryCallback(); @@ -60,8 +63,8 @@ private: union { - std::future<QueryResult> _string; - std::future<PreparedQueryResult> _prepared; + QueryResultFuture _string; + PreparedQueryResultFuture _prepared; }; bool _isPrepared; diff --git a/src/server/database/Database/QueryHolder.cpp b/src/server/database/Database/QueryHolder.cpp index 6a8bb701a1f..4f62ba4810c 100644 --- a/src/server/database/Database/QueryHolder.cpp +++ b/src/server/database/Database/QueryHolder.cpp @@ -19,26 +19,7 @@ #include "QueryHolder.h" #include "PreparedStatement.h" #include "Log.h" - -bool SQLQueryHolder::SetQuery(size_t index, const char *sql) -{ - if (m_queries.size() <= index) - { - TC_LOG_ERROR("sql.sql", "Query index (%u) out of range (size: %u) for query: %s", uint32(index), (uint32)m_queries.size(), sql); - return false; - } - - /// not executed yet, just stored (it's not called a holder for nothing) - SQLElementData element; - element.type = SQL_ELEMENT_RAW; - element.element.query = strdup(sql); - - SQLResultSetUnion result; - result.qresult = NULL; - - m_queries[index] = SQLResultPair(element, result); - return true; -} +#include "QueryResult.h" bool SQLQueryHolder::SetPreparedQuery(size_t index, PreparedStatement* stmt) { @@ -48,59 +29,17 @@ bool SQLQueryHolder::SetPreparedQuery(size_t index, PreparedStatement* stmt) return false; } - /// not executed yet, just stored (it's not called a holder for nothing) - SQLElementData element; - element.type = SQL_ELEMENT_PREPARED; - element.element.stmt = stmt; - - SQLResultSetUnion result; - result.presult = NULL; - - m_queries[index] = SQLResultPair(element, result); + m_queries[index].first = stmt; return true; } -QueryResult SQLQueryHolder::GetResult(size_t index) -{ - // Don't call to this function if the index is of an ad-hoc statement - if (index < m_queries.size()) - { - ResultSet* result = m_queries[index].second.qresult; - if (!result || !result->GetRowCount() || !result->NextRow()) - return QueryResult(NULL); - - return QueryResult(result); - } - else - return QueryResult(NULL); -} - PreparedQueryResult SQLQueryHolder::GetPreparedResult(size_t index) { // Don't call to this function if the index is of a prepared statement if (index < m_queries.size()) - { - PreparedResultSet* result = m_queries[index].second.presult; - if (!result || !result->GetRowCount()) - return PreparedQueryResult(NULL); - - return PreparedQueryResult(result); - } + return m_queries[index].second; else - return PreparedQueryResult(NULL); -} - -void SQLQueryHolder::SetResult(size_t index, ResultSet* result) -{ - if (result && !result->GetRowCount()) - { - delete result; - result = NULL; - } - - /// store the result in the holder - if (index < m_queries.size()) - m_queries[index].second.qresult = result; + return PreparedQueryResult(nullptr); } void SQLQueryHolder::SetPreparedResult(size_t index, PreparedResultSet* result) @@ -113,7 +52,7 @@ void SQLQueryHolder::SetPreparedResult(size_t index, PreparedResultSet* result) /// store the result in the holder if (index < m_queries.size()) - m_queries[index].second.presult = result; + m_queries[index].second = PreparedQueryResult(result); } SQLQueryHolder::~SQLQueryHolder() @@ -122,18 +61,7 @@ SQLQueryHolder::~SQLQueryHolder() { /// if the result was never used, free the resources /// results used already (getresult called) are expected to be deleted - if (SQLElementData* data = &m_queries[i].first) - { - switch (data->type) - { - case SQL_ELEMENT_RAW: - free((void*)(const_cast<char*>(data->element.query))); - break; - case SQL_ELEMENT_PREPARED: - delete data->element.stmt; - break; - } - } + delete m_queries[i].first; } } @@ -156,33 +84,10 @@ bool SQLQueryHolderTask::Execute() if (!m_holder) return false; - /// 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 - if (SQLElementData* data = &queries[i].first) - { - switch (data->type) - { - case SQL_ELEMENT_RAW: - { - char const* sql = data->element.query; - if (sql) - m_holder->SetResult(i, m_conn->Query(sql)); - break; - } - case SQL_ELEMENT_PREPARED: - { - PreparedStatement* stmt = data->element.stmt; - if (stmt) - m_holder->SetPreparedResult(i, m_conn->Query(stmt)); - break; - } - } - } - } + /// execute all queries in the holder and pass the results + for (size_t i = 0; i < m_holder->m_queries.size(); i++) + if (PreparedStatement* stmt = m_holder->m_queries[i].first) + m_holder->SetPreparedResult(i, m_conn->Query(stmt)); m_result.set_value(m_holder); return true; diff --git a/src/server/database/Database/QueryHolder.h b/src/server/database/Database/QueryHolder.h index c3ebb33068c..123765b01a5 100644 --- a/src/server/database/Database/QueryHolder.h +++ b/src/server/database/Database/QueryHolder.h @@ -18,34 +18,22 @@ #ifndef _QUERYHOLDER_H #define _QUERYHOLDER_H -#include <future> +#include "SQLOperation.h" class TC_DATABASE_API SQLQueryHolder { friend class SQLQueryHolderTask; private: - typedef std::pair<SQLElementData, SQLResultSetUnion> SQLResultPair; - std::vector<SQLResultPair> m_queries; + std::vector<std::pair<PreparedStatement*, PreparedQueryResult>> m_queries; public: SQLQueryHolder() { } virtual ~SQLQueryHolder(); - bool SetQuery(size_t index, const char* sql); - template<typename Format, typename... Args> - bool SetPQuery(size_t index, Format&& sql, Args&&... args) - { - return SetQuery(index, Trinity::StringFormat(std::forward<Format>(sql), std::forward<Args>(args)...).c_str()); - } bool SetPreparedQuery(size_t index, PreparedStatement* stmt); void SetSize(size_t size); - QueryResult GetResult(size_t index); PreparedQueryResult GetPreparedResult(size_t index); - void SetResult(size_t index, ResultSet* result); void SetPreparedResult(size_t index, PreparedResultSet* result); }; -typedef std::future<SQLQueryHolder*> QueryResultHolderFuture; -typedef std::promise<SQLQueryHolder*> QueryResultHolderPromise; - class TC_DATABASE_API SQLQueryHolderTask : public SQLOperation { private: diff --git a/src/server/database/Database/QueryResult.cpp b/src/server/database/Database/QueryResult.cpp index 7b6937e50b7..b44768e709d 100644 --- a/src/server/database/Database/QueryResult.cpp +++ b/src/server/database/Database/QueryResult.cpp @@ -16,8 +16,105 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "DatabaseEnv.h" +#include "QueryResult.h" +#include "Errors.h" +#include "Field.h" #include "Log.h" +#include <mysql.h> + +static uint32 SizeForType(MYSQL_FIELD* field) +{ + switch (field->type) + { + case MYSQL_TYPE_NULL: + return 0; + case MYSQL_TYPE_TINY: + return 1; + case MYSQL_TYPE_YEAR: + case MYSQL_TYPE_SHORT: + return 2; + case MYSQL_TYPE_INT24: + case MYSQL_TYPE_LONG: + case MYSQL_TYPE_FLOAT: + return 4; + case MYSQL_TYPE_DOUBLE: + case MYSQL_TYPE_LONGLONG: + case MYSQL_TYPE_BIT: + return 8; + + case MYSQL_TYPE_TIMESTAMP: + case MYSQL_TYPE_DATE: + case MYSQL_TYPE_TIME: + case MYSQL_TYPE_DATETIME: + return sizeof(MYSQL_TIME); + + case MYSQL_TYPE_TINY_BLOB: + case MYSQL_TYPE_MEDIUM_BLOB: + case MYSQL_TYPE_LONG_BLOB: + case MYSQL_TYPE_BLOB: + case MYSQL_TYPE_STRING: + case MYSQL_TYPE_VAR_STRING: + return field->max_length + 1; + + case MYSQL_TYPE_DECIMAL: + case MYSQL_TYPE_NEWDECIMAL: + return 64; + + case MYSQL_TYPE_GEOMETRY: + /* + Following types are not sent over the wire: + MYSQL_TYPE_ENUM: + MYSQL_TYPE_SET: + */ + default: + TC_LOG_WARN("sql.sql", "SQL::SizeForType(): invalid field type %u", uint32(field->type)); + return 0; + } +} + +DatabaseFieldTypes MysqlTypeToFieldType(enum_field_types type) +{ + switch (type) + { + case MYSQL_TYPE_NULL: + return DatabaseFieldTypes::Null; + case MYSQL_TYPE_TINY: + return DatabaseFieldTypes::Int8; + case MYSQL_TYPE_YEAR: + case MYSQL_TYPE_SHORT: + return DatabaseFieldTypes::Int16; + case MYSQL_TYPE_INT24: + case MYSQL_TYPE_LONG: + return DatabaseFieldTypes::Int32; + case MYSQL_TYPE_LONGLONG: + case MYSQL_TYPE_BIT: + return DatabaseFieldTypes::Int64; + case MYSQL_TYPE_FLOAT: + return DatabaseFieldTypes::Float; + case MYSQL_TYPE_DOUBLE: + return DatabaseFieldTypes::Double; + case MYSQL_TYPE_DECIMAL: + case MYSQL_TYPE_NEWDECIMAL: + return DatabaseFieldTypes::Decimal; + case MYSQL_TYPE_TIMESTAMP: + case MYSQL_TYPE_DATE: + case MYSQL_TYPE_TIME: + case MYSQL_TYPE_DATETIME: + return DatabaseFieldTypes::Date; + case MYSQL_TYPE_TINY_BLOB: + case MYSQL_TYPE_MEDIUM_BLOB: + case MYSQL_TYPE_LONG_BLOB: + case MYSQL_TYPE_BLOB: + case MYSQL_TYPE_STRING: + case MYSQL_TYPE_VAR_STRING: + return DatabaseFieldTypes::Binary; + default: + TC_LOG_WARN("sql.sql", "MysqlTypeToFieldType(): invalid field type %u", uint32(type)); + break; + } + + return DatabaseFieldTypes::Null; +} ResultSet::ResultSet(MYSQL_RES *result, MYSQL_FIELD *fields, uint64 rowCount, uint32 fieldCount) : _rowCount(rowCount), @@ -38,9 +135,7 @@ m_rowPosition(0), m_fieldCount(fieldCount), m_rBind(NULL), m_stmt(stmt), -m_metadataResult(result), -m_isNull(NULL), -m_length(NULL) +m_metadataResult(result) { if (!m_metadataResult) return; @@ -52,8 +147,12 @@ m_length(NULL) } m_rBind = new MYSQL_BIND[m_fieldCount]; - m_isNull = new my_bool[m_fieldCount]; - m_length = new unsigned long[m_fieldCount]; + + //- for future readers wondering where the fuck this is freed - mysql_stmt_bind_result moves pointers to these + // from m_rBind to m_stmt->bind and it is later freed by the `if (m_stmt->bind_result_done)` block just above here + // MYSQL_STMT lifetime is equal to connection lifetime + my_bool* m_isNull = new my_bool[m_fieldCount]; + unsigned long* m_length = new unsigned long[m_fieldCount]; memset(m_isNull, 0, sizeof(my_bool) * m_fieldCount); memset(m_rBind, 0, sizeof(MYSQL_BIND) * m_fieldCount); @@ -76,7 +175,7 @@ m_length(NULL) std::size_t rowSize = 0; for (uint32 i = 0; i < m_fieldCount; ++i) { - uint32 size = Field::SizeForType(&field[i]); + uint32 size = SizeForType(&field[i]); rowSize += size; m_rBind[i].buffer_type = field[i].type; @@ -137,7 +236,7 @@ m_length(NULL) m_rows[uint32(m_rowPosition) * m_fieldCount + fIndex].SetByteValue( buffer, - m_rBind[fIndex].buffer_type, + MysqlTypeToFieldType(m_rBind[fIndex].buffer_type), fetched_length); // move buffer pointer to next part @@ -147,7 +246,7 @@ m_length(NULL) { m_rows[uint32(m_rowPosition) * m_fieldCount + fIndex].SetByteValue( nullptr, - m_rBind[fIndex].buffer_type, + MysqlTypeToFieldType(m_rBind[fIndex].buffer_type), *m_rBind[fIndex].length); } @@ -196,7 +295,7 @@ bool ResultSet::NextRow() } for (uint32 i = 0; i < _fieldCount; i++) - _currentRow[i].SetStructuredValue(row[i], _fields[i].type, lengths[i]); + _currentRow[i].SetStructuredValue(row[i], MysqlTypeToFieldType(_fields[i].type), lengths[i]); return true; } @@ -249,3 +348,23 @@ void PreparedResultSet::CleanUp() m_rBind = nullptr; } } + +Field const& ResultSet::operator[](std::size_t index) const +{ + ASSERT(index < _fieldCount); + return _currentRow[index]; +} + +Field* PreparedResultSet::Fetch() const +{ + ASSERT(m_rowPosition < m_rowCount); + return const_cast<Field*>(&m_rows[uint32(m_rowPosition) * m_fieldCount]); +} + +Field const& PreparedResultSet::operator[](std::size_t index) const +{ + ASSERT(m_rowPosition < m_rowCount); + ASSERT(index < m_fieldCount); + return m_rows[uint32(m_rowPosition) * m_fieldCount + index]; +} + diff --git a/src/server/database/Database/QueryResult.h b/src/server/database/Database/QueryResult.h index 5d2cc425ae8..dcfe18765fc 100644 --- a/src/server/database/Database/QueryResult.h +++ b/src/server/database/Database/QueryResult.h @@ -19,14 +19,9 @@ #ifndef QUERYRESULT_H #define QUERYRESULT_H -#include <memory> -#include "Errors.h" -#include "Field.h" - -#ifdef _WIN32 - #include <winsock2.h> -#endif -#include <mysql.h> +#include "Define.h" +#include "DatabaseEnvFwd.h" +#include <vector> class TC_DATABASE_API ResultSet { @@ -39,11 +34,7 @@ class TC_DATABASE_API ResultSet uint32 GetFieldCount() const { return _fieldCount; } Field* Fetch() const { return _currentRow; } - const Field & operator [] (uint32 index) const - { - ASSERT(index < _fieldCount); - return _currentRow[index]; - } + Field const& operator[](std::size_t index) const; protected: uint64 _rowCount; @@ -59,8 +50,6 @@ class TC_DATABASE_API ResultSet ResultSet& operator=(ResultSet const& right) = delete; }; -typedef std::shared_ptr<ResultSet> QueryResult; - class TC_DATABASE_API PreparedResultSet { public: @@ -71,18 +60,8 @@ class TC_DATABASE_API PreparedResultSet uint64 GetRowCount() const { return m_rowCount; } uint32 GetFieldCount() const { return m_fieldCount; } - Field* Fetch() const - { - ASSERT(m_rowPosition < m_rowCount); - return const_cast<Field*>(&m_rows[uint32(m_rowPosition) * m_fieldCount]); - } - - Field const& operator[](uint32 index) const - { - ASSERT(m_rowPosition < m_rowCount); - ASSERT(index < m_fieldCount); - return m_rows[uint32(m_rowPosition) * m_fieldCount + index]; - } + Field* Fetch() const; + Field const& operator[](std::size_t index) const; protected: std::vector<Field> m_rows; @@ -95,9 +74,6 @@ class TC_DATABASE_API PreparedResultSet MYSQL_STMT* m_stmt; MYSQL_RES* m_metadataResult; ///< Field metadata, returned by mysql_stmt_result_metadata - my_bool* m_isNull; - unsigned long* m_length; - void CleanUp(); bool _NextRow(); @@ -105,7 +81,4 @@ class TC_DATABASE_API PreparedResultSet PreparedResultSet& operator=(PreparedResultSet const& right) = delete; }; -typedef std::shared_ptr<PreparedResultSet> PreparedQueryResult; - #endif - diff --git a/src/server/database/Database/SQLOperation.h b/src/server/database/Database/SQLOperation.h index 1e3000600c5..b0417bb1936 100644 --- a/src/server/database/Database/SQLOperation.h +++ b/src/server/database/Database/SQLOperation.h @@ -18,10 +18,8 @@ #ifndef _SQLOPERATION_H #define _SQLOPERATION_H -#include "QueryResult.h" - -//- Forward declare (don't include header to prevent circular includes) -class PreparedStatement; +#include "Define.h" +#include "DatabaseEnvFwd.h" //- Union that holds element data union SQLElementUnion diff --git a/src/server/database/Database/Transaction.cpp b/src/server/database/Database/Transaction.cpp index 52f7062c78a..c59d6d4d8ae 100644 --- a/src/server/database/Database/Transaction.cpp +++ b/src/server/database/Database/Transaction.cpp @@ -15,8 +15,9 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "DatabaseEnv.h" #include "Transaction.h" +#include "MySQLConnection.h" +#include "PreparedStatement.h" #include <mysqld_error.h> std::mutex TransactionTask::_deadlockLock; @@ -45,9 +46,8 @@ void Transaction::Cleanup() if (_cleanedUp) return; - while (!m_queries.empty()) + for (SQLElementData const &data : m_queries) { - SQLElementData const &data = m_queries.front(); switch (data.type) { case SQL_ELEMENT_PREPARED: @@ -57,10 +57,9 @@ void Transaction::Cleanup() free((void*)(data.element.query)); break; } - - m_queries.pop_front(); } + m_queries.clear(); _cleanedUp = true; } diff --git a/src/server/database/Database/Transaction.h b/src/server/database/Database/Transaction.h index fbb96c053ce..d2c64c9451a 100644 --- a/src/server/database/Database/Transaction.h +++ b/src/server/database/Database/Transaction.h @@ -18,13 +18,12 @@ #ifndef _TRANSACTION_H #define _TRANSACTION_H +#include "Define.h" +#include "DatabaseEnvFwd.h" #include "SQLOperation.h" #include "StringFormat.h" -#include <list> #include <mutex> - -//- Forward declare (don't include header to prevent circular includes) -class PreparedStatement; +#include <vector> /*! Transactions, high level class. */ class TC_DATABASE_API Transaction @@ -47,17 +46,16 @@ class TC_DATABASE_API Transaction Append(Trinity::StringFormat(std::forward<Format>(sql), std::forward<Args>(args)...).c_str()); } - size_t GetSize() const { return m_queries.size(); } + std::size_t GetSize() const { return m_queries.size(); } protected: void Cleanup(); - std::list<SQLElementData> m_queries; + std::vector<SQLElementData> m_queries; private: bool _cleanedUp; }; -typedef std::shared_ptr<Transaction> SQLTransaction; /*! Low level class*/ class TC_DATABASE_API TransactionTask : public SQLOperation diff --git a/src/server/database/Logging/AppenderDB.cpp b/src/server/database/Logging/AppenderDB.cpp index f14bb04ddea..3552a1da4e1 100644 --- a/src/server/database/Logging/AppenderDB.cpp +++ b/src/server/database/Logging/AppenderDB.cpp @@ -16,7 +16,9 @@ */ #include "AppenderDB.h" -#include "Database/DatabaseEnv.h" +#include "DatabaseEnv.h" +#include "LogMessage.h" +#include "PreparedStatement.h" #include "LogMessage.h" AppenderDB::AppenderDB(uint8 id, std::string const& name, LogLevel level, AppenderFlags /*flags*/, std::vector<char const*> /*extraArgs*/) diff --git a/src/server/database/PrecompiledHeaders/databasePCH.h b/src/server/database/PrecompiledHeaders/databasePCH.h index d524d52ade0..60f57abf949 100644 --- a/src/server/database/PrecompiledHeaders/databasePCH.h +++ b/src/server/database/PrecompiledHeaders/databasePCH.h @@ -1,23 +1,12 @@ -#include "Config.h" -#include "Database/AdhocStatement.h" -#include "Database/DatabaseEnv.h" -#include "Database/DatabaseLoader.h" -#include "Database/DatabaseWorker.h" -#include "Database/DatabaseWorkerPool.h" -#include "Database/Field.h" -#include "Database/MySQLConnection.h" -#include "Database/MySQLThreading.h" -#include "Database/PreparedStatement.h" -#include "Database/QueryHolder.h" -#include "Database/QueryResult.h" -#include "Database/SQLOperation.h" -#include "Database/Transaction.h" -#include "Logging/Appender.h" -#include "Logging/AppenderConsole.h" -#include "Logging/AppenderDB.h" -#include "Logging/AppenderFile.h" -#include "Logging/Log.h" -#include "Logging/LogOperation.h" -#include "Logging/Logger.h" -#include "Updater/DBUpdater.h" -#include "Updater/UpdateFetcher.h" +#include "Define.h" +#include "Errors.h" +#include "Field.h" +#include "Log.h" +#include "MySQLConnection.h" +#include "PreparedStatement.h" +#include "QueryResult.h" +#include "SQLOperation.h" +#include "Transaction.h" +#include <mysql.h> +#include <string> +#include <vector> diff --git a/src/server/database/Updater/DBUpdater.cpp b/src/server/database/Updater/DBUpdater.cpp index 117c3097478..5b0d6ca9de8 100644 --- a/src/server/database/Updater/DBUpdater.cpp +++ b/src/server/database/Updater/DBUpdater.cpp @@ -16,17 +16,18 @@ */ #include "DBUpdater.h" -#include "Log.h" -#include "GitRevision.h" -#include "UpdateFetcher.h" -#include "DatabaseLoader.h" -#include "Config.h" #include "BuiltInConfig.h" +#include "Config.h" +#include "DatabaseEnv.h" +#include "DatabaseLoader.h" +#include "GitRevision.h" +#include "Log.h" +#include "QueryResult.h" #include "StartProcess.h" - +#include "UpdateFetcher.h" +#include <boost/filesystem/operations.hpp> #include <fstream> #include <iostream> -#include <unordered_map> std::string DBUpdaterUtil::GetCorrectedMySQLExecutable() { diff --git a/src/server/database/Updater/DBUpdater.h b/src/server/database/Updater/DBUpdater.h index fdc00c9d6b6..8cea468e3cd 100644 --- a/src/server/database/Updater/DBUpdater.h +++ b/src/server/database/Updater/DBUpdater.h @@ -18,10 +18,20 @@ #ifndef DBUpdater_h__ #define DBUpdater_h__ -#include "DatabaseEnv.h" - +#include "Define.h" +#include "DatabaseEnvFwd.h" #include <string> -#include <boost/filesystem.hpp> + +template <class T> +class DatabaseWorkerPool; + +namespace boost +{ + namespace filesystem + { + class path; + } +} class TC_DATABASE_API UpdateException : public std::exception { @@ -41,19 +51,6 @@ enum BaseLocation LOCATION_DOWNLOAD }; -struct TC_DATABASE_API UpdateResult -{ - UpdateResult() - : updated(0), recent(0), archived(0) { } - - UpdateResult(size_t const updated_, size_t const recent_, size_t const archived_) - : updated(updated_), recent(recent_), archived(archived_) { } - - size_t updated; - size_t recent; - size_t archived; -}; - class DBUpdaterUtil { public: diff --git a/src/server/database/Updater/UpdateFetcher.cpp b/src/server/database/Updater/UpdateFetcher.cpp index 1da370ee7b9..3155427f78e 100644 --- a/src/server/database/Updater/UpdateFetcher.cpp +++ b/src/server/database/Updater/UpdateFetcher.cpp @@ -16,28 +16,41 @@ */ #include "UpdateFetcher.h" +#include "Common.h" +#include "DBUpdater.h" +#include "Field.h" #include "Log.h" +#include "QueryResult.h" #include "Util.h" #include "SHA1.h" - +#include <boost/filesystem/operations.hpp> #include <fstream> -#include <chrono> -#include <vector> #include <sstream> -#include <exception> -#include <unordered_map> using namespace boost::filesystem; +struct UpdateFetcher::DirectoryEntry +{ + DirectoryEntry(Path const& path_, State state_) : path(path_), state(state_) { } + + Path const path; + + State const state; +}; + UpdateFetcher::UpdateFetcher(Path const& sourceDirectory, std::function<void(std::string const&)> const& apply, std::function<void(Path const& path)> const& applyFile, std::function<QueryResult(std::string const&)> const& retrieve) : - _sourceDirectory(sourceDirectory), _apply(apply), _applyFile(applyFile), + _sourceDirectory(Trinity::make_unique<Path>(sourceDirectory)), _apply(apply), _applyFile(applyFile), _retrieve(retrieve) { } +UpdateFetcher::~UpdateFetcher() +{ +} + UpdateFetcher::LocaleFileStorage UpdateFetcher::GetFileList() const { LocaleFileStorage files; @@ -95,7 +108,7 @@ UpdateFetcher::DirectoryStorage UpdateFetcher::ReceiveIncludedDirectories() cons std::string path = fields[0].GetString(); if (path.substr(0, 1) == "$") - path = _sourceDirectory.generic_string() + path.substr(1); + path = _sourceDirectory->generic_string() + path.substr(1); Path const p(path); @@ -405,3 +418,8 @@ void UpdateFetcher::UpdateState(std::string const& name, State const state) cons // Update database _apply(update); } + +bool UpdateFetcher::PathCompare::operator()(LocaleFileEntry const& left, LocaleFileEntry const& right) const +{ + return left.first.filename().string() < right.first.filename().string(); +} diff --git a/src/server/database/Updater/UpdateFetcher.h b/src/server/database/Updater/UpdateFetcher.h index 0ca18f43886..f5187d261a7 100644 --- a/src/server/database/Updater/UpdateFetcher.h +++ b/src/server/database/Updater/UpdateFetcher.h @@ -18,14 +18,35 @@ #ifndef UpdateFetcher_h__ #define UpdateFetcher_h__ -#include <DBUpdater.h> - -#include <functional> +#include "Define.h" +#include "DatabaseEnvFwd.h" +#include <set> #include <string> -#include <memory> +#include <unordered_map> #include <set> #include <vector> +namespace boost +{ + namespace filesystem + { + class path; + } +} + +struct TC_DATABASE_API UpdateResult +{ + UpdateResult() + : updated(0), recent(0), archived(0) { } + + UpdateResult(size_t const updated_, size_t const recent_, size_t const archived_) + : updated(updated_), recent(recent_), archived(archived_) { } + + size_t updated; + size_t recent; + size_t archived; +}; + class TC_DATABASE_API UpdateFetcher { typedef boost::filesystem::path Path; @@ -35,6 +56,7 @@ public: std::function<void(std::string const&)> const& apply, std::function<void(Path const& path)> const& applyFile, std::function<QueryResult(std::string const&)> const& retrieve); + ~UpdateFetcher(); UpdateResult Update(bool const redundancyChecks, bool const allowRehash, bool const archivedRedundancy, int32 const cleanDeadReferencesMaxCount) const; @@ -81,23 +103,13 @@ private: } }; - struct DirectoryEntry - { - DirectoryEntry(Path const& path_, State state_) : path(path_), state(state_) { } - - Path const path; - - State const state; - }; + struct DirectoryEntry; typedef std::pair<Path, State> LocaleFileEntry; struct PathCompare { - inline bool operator() (LocaleFileEntry const& left, LocaleFileEntry const& right) const - { - return left.first.filename().string() < right.first.filename().string(); - } + bool operator()(LocaleFileEntry const& left, LocaleFileEntry const& right) const; }; typedef std::set<LocaleFileEntry, PathCompare> LocaleFileStorage; @@ -122,7 +134,7 @@ private: void UpdateState(std::string const& name, State const state) const; - Path const _sourceDirectory; + std::unique_ptr<Path> const _sourceDirectory; std::function<void(std::string const&)> const _apply; std::function<void(Path const& path)> const _applyFile; |