aboutsummaryrefslogtreecommitdiff
path: root/src/server/database/Database
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/database/Database')
-rw-r--r--src/server/database/Database/AdhocStatement.cpp8
-rw-r--r--src/server/database/Database/AdhocStatement.h10
-rw-r--r--src/server/database/Database/DatabaseEnv.cpp6
-rw-r--r--src/server/database/Database/DatabaseEnv.h28
-rw-r--r--src/server/database/Database/DatabaseEnvFwd.h54
-rw-r--r--src/server/database/Database/DatabaseLoader.cpp10
-rw-r--r--src/server/database/Database/DatabaseLoader.h9
-rw-r--r--src/server/database/Database/DatabaseWorker.cpp1
-rw-r--r--src/server/database/Database/DatabaseWorker.h8
-rw-r--r--src/server/database/Database/DatabaseWorkerPool.cpp134
-rw-r--r--src/server/database/Database/DatabaseWorkerPool.h123
-rw-r--r--src/server/database/Database/Field.cpp305
-rw-r--r--src/server/database/Database/Field.h388
-rw-r--r--src/server/database/Database/Implementation/CharacterDatabase.cpp13
-rw-r--r--src/server/database/Database/Implementation/CharacterDatabase.h10
-rw-r--r--src/server/database/Database/Implementation/LoginDatabase.cpp17
-rw-r--r--src/server/database/Database/Implementation/LoginDatabase.h10
-rw-r--r--src/server/database/Database/Implementation/WorldDatabase.cpp13
-rw-r--r--src/server/database/Database/Implementation/WorldDatabase.h10
-rw-r--r--src/server/database/Database/MySQLConnection.cpp91
-rw-r--r--src/server/database/Database/MySQLConnection.h66
-rw-r--r--src/server/database/Database/MySQLThreading.cpp32
-rw-r--r--src/server/database/Database/MySQLThreading.h18
-rw-r--r--src/server/database/Database/PreparedStatement.cpp89
-rw-r--r--src/server/database/Database/PreparedStatement.h12
-rw-r--r--src/server/database/Database/QueryCallback.cpp11
-rw-r--r--src/server/database/Database/QueryCallback.h15
-rw-r--r--src/server/database/Database/QueryHolder.cpp117
-rw-r--r--src/server/database/Database/QueryHolder.h16
-rw-r--r--src/server/database/Database/QueryResult.cpp149
-rw-r--r--src/server/database/Database/QueryResult.h38
-rw-r--r--src/server/database/Database/SQLOperation.h10
-rw-r--r--src/server/database/Database/Transaction.cpp11
-rw-r--r--src/server/database/Database/Transaction.h14
34 files changed, 1005 insertions, 841 deletions
diff --git a/src/server/database/Database/AdhocStatement.cpp b/src/server/database/Database/AdhocStatement.cpp
index 644af01787b..90ddc1630f4 100644
--- a/src/server/database/Database/AdhocStatement.cpp
+++ b/src/server/database/Database/AdhocStatement.cpp
@@ -16,10 +16,14 @@
*/
#include "AdhocStatement.h"
+#include "Errors.h"
#include "MySQLConnection.h"
+#include "QueryResult.h"
+#include <cstdlib>
+#include <cstring>
/*! Basic, ad-hoc queries. */
-BasicStatementTask::BasicStatementTask(const char* sql, bool async) :
+BasicStatementTask::BasicStatementTask(char const* sql, bool async) :
m_result(nullptr)
{
m_sql = strdup(sql);
@@ -43,7 +47,7 @@ bool BasicStatementTask::Execute()
if (!result || !result->GetRowCount() || !result->NextRow())
{
delete result;
- m_result->set_value(QueryResult(NULL));
+ m_result->set_value(QueryResult(nullptr));
return false;
}
diff --git a/src/server/database/Database/AdhocStatement.h b/src/server/database/Database/AdhocStatement.h
index e419908d175..e42e3474df3 100644
--- a/src/server/database/Database/AdhocStatement.h
+++ b/src/server/database/Database/AdhocStatement.h
@@ -18,24 +18,22 @@
#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
{
public:
- BasicStatementTask(const char* sql, bool async = false);
+ BasicStatementTask(char const* sql, bool async = false);
~BasicStatementTask();
bool Execute() override;
QueryResultFuture GetFuture() const { return m_result->get_future(); }
private:
- const char* m_sql; //- Raw query to be executed
+ char const* m_sql; //- Raw query to be executed
bool m_has_result;
QueryResultPromise* m_result;
};
diff --git a/src/server/database/Database/DatabaseEnv.cpp b/src/server/database/Database/DatabaseEnv.cpp
index 21b937d3c76..c7419f95de8 100644
--- a/src/server/database/Database/DatabaseEnv.cpp
+++ b/src/server/database/Database/DatabaseEnv.cpp
@@ -17,6 +17,6 @@
#include "DatabaseEnv.h"
-WorldDatabaseWorkerPool WorldDatabase;
-CharacterDatabaseWorkerPool CharacterDatabase;
-LoginDatabaseWorkerPool LoginDatabase;
+DatabaseWorkerPool<WorldDatabaseConnection> WorldDatabase;
+DatabaseWorkerPool<CharacterDatabaseConnection> CharacterDatabase;
+DatabaseWorkerPool<LoginDatabaseConnection> LoginDatabase;
diff --git a/src/server/database/Database/DatabaseEnv.h b/src/server/database/Database/DatabaseEnv.h
index dde0d5f1847..301b94567ce 100644
--- a/src/server/database/Database/DatabaseEnv.h
+++ b/src/server/database/Database/DatabaseEnv.h
@@ -19,30 +19,24 @@
#ifndef DATABASEENV_H
#define DATABASEENV_H
-#include "Common.h"
-#include "Errors.h"
-#include "Log.h"
-
-#include "Field.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 "Define.h"
+#include "DatabaseWorkerPool.h"
#include "Implementation/LoginDatabase.h"
#include "Implementation/CharacterDatabase.h"
#include "Implementation/WorldDatabase.h"
+#include "Field.h"
+#include "PreparedStatement.h"
+#include "QueryCallback.h"
+#include "QueryResult.h"
+#include "Transaction.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;
#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 31e4b63f46c..6dd5003cc4b 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,8 +180,8 @@ 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<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 472a6811f31..78125b9ac7e 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 fca4f666310..2d8c22e4d6f 100644
--- a/src/server/database/Database/DatabaseWorkerPool.cpp
+++ b/src/server/database/Database/DatabaseWorkerPool.cpp
@@ -16,12 +16,39 @@
*/
#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 "Log.h"
+#include "PreparedStatement.h"
+#include "ProducerConsumerQueue.h"
#include "QueryCallback.h"
+#include "QueryHolder.h"
+#include "QueryResult.h"
+#include "SQLOperation.h"
+#include "Transaction.h"
+#ifdef _WIN32 // hack for broken mysql.h not including the correct winsock header for SOCKET definition, fixed in 5.7
+#include <winsock2.h>
+#endif
+#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*>()),
@@ -34,6 +61,12 @@ DatabaseWorkerPool<T>::DatabaseWorkerPool()
}
template <class T>
+DatabaseWorkerPool<T>::~DatabaseWorkerPool()
+{
+ _queue->Cancel();
+}
+
+template <class T>
void DatabaseWorkerPool<T>::SetConnectionInfo(std::string const& infoString,
uint8 const asyncThreads, uint8 const synchThreads)
{
@@ -135,7 +168,7 @@ bool DatabaseWorkerPool<T>::PrepareStatements()
}
template <class T>
-QueryResult DatabaseWorkerPool<T>::Query(const char* sql, T* connection /*= nullptr*/)
+QueryResult DatabaseWorkerPool<T>::Query(char const* sql, T* connection /*= nullptr*/)
{
if (!connection)
connection = GetFreeConnection();
@@ -145,7 +178,7 @@ QueryResult DatabaseWorkerPool<T>::Query(const char* sql, T* connection /*= null
if (!result || !result->GetRowCount() || !result->NextRow())
{
delete result;
- return QueryResult(NULL);
+ return QueryResult(nullptr);
}
return QueryResult(result);
@@ -164,14 +197,14 @@ PreparedQueryResult DatabaseWorkerPool<T>::Query(PreparedStatement* stmt)
if (!ret || !ret->GetRowCount())
{
delete ret;
- return PreparedQueryResult(NULL);
+ return PreparedQueryResult(nullptr);
}
return PreparedQueryResult(ret);
}
template <class T>
-QueryCallback DatabaseWorkerPool<T>::AsyncQuery(const char* sql)
+QueryCallback DatabaseWorkerPool<T>::AsyncQuery(char const* sql)
{
BasicStatementTask* task = new BasicStatementTask(sql, true);
// Store future result before enqueueing - task might get already processed and deleted before returning from this method
@@ -201,6 +234,12 @@ QueryResultHolderFuture DatabaseWorkerPool<T>::DelayQueryHolder(SQLQueryHolder*
}
template <class T>
+SQLTransaction DatabaseWorkerPool<T>::BeginTransaction()
+{
+ return std::make_shared<Transaction>();
+}
+
+template <class T>
void DatabaseWorkerPool<T>::CommitTransaction(SQLTransaction transaction)
{
#ifdef TRINITY_DEBUG
@@ -253,6 +292,12 @@ void DatabaseWorkerPool<T>::DirectCommitTransaction(SQLTransaction& transaction)
}
template <class T>
+PreparedStatement* DatabaseWorkerPool<T>::GetPreparedStatement(PreparedStatementIndex index)
+{
+ return new PreparedStatement(index, _preparedStatementSize[index]);
+}
+
+template <class T>
void DatabaseWorkerPool<T>::EscapeString(std::string& str)
{
if (str.empty())
@@ -325,6 +370,22 @@ uint32 DatabaseWorkerPool<T>::OpenConnections(InternalIndex type, uint8 numConne
}
template <class T>
+unsigned long DatabaseWorkerPool<T>::EscapeString(char* to, char const* 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;
@@ -342,6 +403,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(char const* 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(char const* 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, char const* 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 b1be44adf32..7b4698a5bce 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
@@ -60,10 +46,7 @@ class DatabaseWorkerPool
/* Activity state */
DatabaseWorkerPool();
- ~DatabaseWorkerPool()
- {
- _queue->Cancel();
- }
+ ~DatabaseWorkerPool();
void SetConnectionInfo(std::string const& infoString, uint8 const asyncThreads, uint8 const synchThreads);
@@ -85,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(char const* 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.
@@ -107,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.
@@ -119,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(char const* 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.
@@ -142,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.
@@ -158,7 +114,7 @@ class DatabaseWorkerPool
//! Directly executes an SQL query in string format that will block the calling thread until finished.
//! Returns reference counted auto pointer, no need for manual memory management in upper level code.
- QueryResult Query(const char* sql, T* connection = nullptr);
+ QueryResult Query(char const* sql, T* connection = nullptr);
//! Directly executes an SQL query in string format -with variable args- that will block the calling thread until finished.
//! Returns reference counted auto pointer, no need for manual memory management in upper level code.
@@ -193,7 +149,7 @@ class DatabaseWorkerPool
//! Enqueues a query in string format that will set the value of the QueryResultFuture return object as soon as the query is executed.
//! The return value is then processed in ProcessQueryCallback methods.
- QueryCallback AsyncQuery(const char* sql);
+ QueryCallback AsyncQuery(char const* sql);
//! Enqueues a query in prepared format that will set the value of the PreparedQueryResultFuture return object as soon as the query is executed.
//! The return value is then processed in ProcessQueryCallback methods.
@@ -211,10 +167,7 @@ class DatabaseWorkerPool
*/
//! Begins an automanaged transaction pointer that will automatically rollback if not commited. (Autocommit=0)
- SQLTransaction BeginTransaction()
- {
- return SQLTransaction(new Transaction);
- }
+ SQLTransaction BeginTransaction();
//! Enqueues a collection of one-way SQL operations (can be both adhoc and prepared). The order in which these operations
//! were appended to the transaction will be respected during execution.
@@ -224,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, char const* 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
@@ -253,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, _preparedStatementSize[index]);
- }
+ PreparedStatement* GetPreparedStatement(PreparedStatementIndex index);
//! Apply escape string'ing for current collation. (utf8)
void EscapeString(std::string& str);
@@ -267,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;
+ unsigned long EscapeString(char* to, char const* from, unsigned long length);
- return mysql_real_escape_string(
- _connections[IDX_SYNCH].front()->GetHandle(), to, from, 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..fee9ff6467d 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.value = nullptr;
+ 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, nullptr, 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, nullptr, 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, nullptr, 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, nullptr, 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 nullptr;
+
+#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 nullptr;
+ }
+#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,70 @@ 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
+
+#ifdef _WIN32 // hack for broken mysql.h not including the correct winsock header for SOCKET definition, fixed in 5.7
+#include <winsock2.h>
+#endif
+#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 4daa447e481..f7f8397b761 100644
--- a/src/server/database/Database/Field.h
+++ b/src/server/database/Database/Field.h
@@ -18,10 +18,23 @@
#ifndef _FIELD_H
#define _FIELD_H
-#include "Common.h"
-#include "Log.h"
+#include "Define.h"
+#include "DatabaseEnvFwd.h"
+#include <vector>
-#include <mysql.h>
+enum class DatabaseFieldTypes : uint8
+{
+ Null,
+ Int8,
+ Int16,
+ Int32,
+ Int64,
+ Float,
+ Double,
+ Decimal,
+ Date,
+ Binary
+};
/**
@class Field
@@ -67,238 +80,23 @@ 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
{
- return data.value == NULL;
+ return data.value == nullptr;
}
struct Metadata
@@ -315,138 +113,32 @@ class TC_DATABASE_API Field
#pragma pack(push, 1)
struct
{
- uint32 length; // Length (prepared strings only)
- void* value; // Actual data in memory
- enum_field_types type; // Field type
- bool raw; // Raw bytes? (Prepared statement or ad hoc)
+ uint32 length; // Length (prepared strings only)
+ void* value; // Actual data in memory
+ 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()
{
// Field does not own the data if fetched with prepared statement
if (!data.raw)
delete[] ((char*)data.value);
- 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;
- }
+ data.value = nullptr;
}
- 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 ca845ccd5a9..398973a7e85 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()
{
@@ -610,3 +611,15 @@ void CharacterDatabaseConnection::DoPrepareStatements()
// DeserterTracker
PrepareStatement(CHAR_INS_DESERTER_TRACK, "INSERT INTO battleground_deserters (guid, type, datetime) VALUES (?, ?, NOW())", 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 28408886a8e..8f59059abc0 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}
@@ -536,13 +535,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/LoginDatabase.cpp b/src/server/database/Database/Implementation/LoginDatabase.cpp
index 360f0648254..3001e4c6df7 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()
{
@@ -63,7 +64,7 @@ void LoginDatabaseConnection::DoPrepareStatements()
PrepareStatement(LOGIN_INS_REALM_CHARACTERS, "INSERT INTO realmcharacters (numchars, acctid, realmid) VALUES (?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(LOGIN_SEL_SUM_REALM_CHARACTERS, "SELECT SUM(numchars) FROM realmcharacters WHERE acctid = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_INS_ACCOUNT, "INSERT INTO account(username, sha_pass_hash, reg_mail, email, joindate) VALUES(?, ?, ?, ?, NOW())", CONNECTION_SYNCH);
- PrepareStatement(LOGIN_INS_REALM_CHARACTERS_INIT, "INSERT INTO realmcharacters (realmid, acctid, numchars) SELECT realmlist.id, account.id, 0 FROM realmlist, account LEFT JOIN realmcharacters ON acctid=account.id WHERE acctid IS NULL", CONNECTION_ASYNC);
+ PrepareStatement(LOGIN_INS_REALM_CHARACTERS_INIT, "INSERT INTO realmcharacters (realmid, acctid, numchars) SELECT realmlist.id, account.id, 0 FROM realmlist, account LEFT JOIN realmcharacters ON acctid = account.id WHERE acctid IS NULL", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_EXPANSION, "UPDATE account SET expansion = ? WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_ACCOUNT_LOCK, "UPDATE account SET locked = ? WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_ACCOUNT_LOCK_CONTRY, "UPDATE account SET lock_country = ? WHERE id = ?", CONNECTION_ASYNC);
@@ -90,7 +91,7 @@ void LoginDatabaseConnection::DoPrepareStatements()
PrepareStatement(LOGIN_SEL_CHECK_PASSWORD_BY_NAME, "SELECT 1 FROM account WHERE username = ? AND sha_pass_hash = ?", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_PINFO, "SELECT a.username, aa.gmlevel, a.email, a.reg_mail, a.last_ip, DATE_FORMAT(a.last_login, '%Y-%m-%d %T'), a.mutetime, a.mutereason, a.muteby, a.failed_logins, a.locked, a.OS FROM account a LEFT JOIN account_access aa ON (a.id = aa.id AND (aa.RealmID = ? OR aa.RealmID = -1)) WHERE a.id = ?", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_PINFO_BANS, "SELECT unbandate, bandate = unbandate, bannedby, banreason FROM account_banned WHERE id = ? AND active ORDER BY bandate ASC LIMIT 1", CONNECTION_SYNCH);
- PrepareStatement(LOGIN_SEL_GM_ACCOUNTS, "SELECT a.username, aa.gmlevel FROM account a, account_access aa WHERE a.id=aa.id AND aa.gmlevel >= ? AND (aa.realmid = -1 OR aa.realmid = ?)", CONNECTION_SYNCH);
+ PrepareStatement(LOGIN_SEL_GM_ACCOUNTS, "SELECT a.username, aa.gmlevel FROM account a, account_access aa WHERE a.id = aa.id AND aa.gmlevel >= ? AND (aa.realmid = -1 OR aa.realmid = ?)", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_ACCOUNT_INFO, "SELECT a.username, a.last_ip, aa.gmlevel, a.expansion FROM account a LEFT JOIN account_access aa ON (a.id = aa.id) WHERE a.id = ?", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_ACCOUNT_ACCESS_GMLEVEL_TEST, "SELECT 1 FROM account_access WHERE id = ? AND gmlevel > ?", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_ACCOUNT_ACCESS, "SELECT a.id, aa.gmlevel, aa.RealmID FROM account a LEFT JOIN account_access aa ON (a.id = aa.id) WHERE a.username = ?", CONNECTION_SYNCH);
@@ -119,3 +120,15 @@ void LoginDatabaseConnection::DoPrepareStatements()
PrepareStatement(LOGIN_SEL_ACCOUNT_MUTE_INFO, "SELECT mutedate, mutetime, mutereason, mutedby FROM account_muted WHERE guid = ? ORDER BY mutedate ASC", CONNECTION_SYNCH);
PrepareStatement(LOGIN_DEL_ACCOUNT_MUTED, "DELETE FROM account_muted WHERE guid = ?", 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 dcb77394b42..f199d81f55c 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}
@@ -123,13 +122,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 c4550144908..c64e7a9c2fc 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_CREATURE_ZONE_AREA_DATA, "UPDATE creature SET zoneId = ?, areaId = ? WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(WORLD_UPD_GAMEOBJECT_ZONE_AREA_DATA, "UPDATE gameobject SET zoneId = ?, areaId = ? WHERE guid = ?", CONNECTION_ASYNC);
}
+
+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 069f5fe0555..b68f53bb173 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 6e862ae6abe..75e6362f87f 100644
--- a/src/server/database/Database/MySQLConnection.cpp
+++ b/src/server/database/Database/MySQLConnection.cpp
@@ -15,29 +15,43 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-
+#include "MySQLConnection.h"
#include "Common.h"
-
-#ifdef _WIN32
- #include <winsock2.h>
+#include "DatabaseWorker.h"
+#include "Log.h"
+#include "PreparedStatement.h"
+#include "QueryResult.h"
+#include "Timer.h"
+#include "Transaction.h"
+#include "Util.h"
+#include <errmsg.h>
+#ifdef _WIN32 // hack for broken mysql.h not including the correct winsock header for SOCKET definition, fixed in 5.7
+#include <winsock2.h>
#endif
#include <mysql.h>
-#include <errmsg.h>
+#include <mysqld_error.h>
-#include "MySQLConnection.h"
-#include "QueryResult.h"
-#include "SQLOperation.h"
-#include "PreparedStatement.h"
-#include "DatabaseWorker.h"
-#include "Timer.h"
-#include "Log.h"
-#include "ProducerConsumerQueue.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),
m_prepareError(false),
-m_queue(NULL),
-m_Mysql(NULL),
+m_queue(nullptr),
+m_Mysql(nullptr),
m_connectionInfo(connInfo),
m_connectionFlags(CONNECTION_SYNCH) { }
@@ -45,7 +59,7 @@ MySQLConnection::MySQLConnection(ProducerConsumerQueue<SQLOperation*>* queue, My
m_reconnecting(false),
m_prepareError(false),
m_queue(queue),
-m_Mysql(NULL),
+m_Mysql(nullptr),
m_connectionInfo(connInfo),
m_connectionFlags(CONNECTION_ASYNC)
{
@@ -74,7 +88,7 @@ void MySQLConnection::Close()
uint32 MySQLConnection::Open()
{
MYSQL *mysqlInit;
- mysqlInit = mysql_init(NULL);
+ mysqlInit = mysql_init(nullptr);
if (!mysqlInit)
{
TC_LOG_ERROR("sql.sql", "Could not initialize Mysql connection to database `%s`", m_connectionInfo.database.c_str());
@@ -152,7 +166,7 @@ bool MySQLConnection::PrepareStatements()
return !m_prepareError;
}
-bool MySQLConnection::Execute(const char* sql)
+bool MySQLConnection::Execute(char const* sql)
{
if (!m_Mysql)
return false;
@@ -281,18 +295,18 @@ bool MySQLConnection::_Query(PreparedStatement* stmt, MYSQL_RES **pResult, uint6
return true;
}
-ResultSet* MySQLConnection::Query(const char* sql)
+ResultSet* MySQLConnection::Query(char const* sql)
{
if (!sql)
- return NULL;
+ return nullptr;
- MYSQL_RES *result = NULL;
- MYSQL_FIELD *fields = NULL;
+ MYSQL_RES *result = nullptr;
+ MYSQL_FIELD *fields = nullptr;
uint64 rowCount = 0;
uint32 fieldCount = 0;
if (!_Query(sql, &result, &fields, &rowCount, &fieldCount))
- return NULL;
+ return nullptr;
return new ResultSet(result, fields, rowCount, fieldCount);
}
@@ -355,14 +369,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)
@@ -382,7 +395,7 @@ int MySQLConnection::ExecuteTransaction(SQLTransaction& transaction)
break;
case SQL_ELEMENT_RAW:
{
- const char* sql = data.element.query;
+ char const* sql = data.element.query;
ASSERT(sql);
if (!Execute(sql))
{
@@ -405,6 +418,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());
@@ -450,12 +483,12 @@ void MySQLConnection::PrepareStatement(uint32 index, std::string const& sql, Con
PreparedResultSet* MySQLConnection::Query(PreparedStatement* stmt)
{
- MYSQL_RES *result = NULL;
+ MYSQL_RES *result = nullptr;
uint64 rowCount = 0;
uint32 fieldCount = 0;
if (!_Query(stmt, &result, &rowCount, &fieldCount))
- return NULL;
+ return nullptr;
if (mysql_more_results(m_Mysql))
{
diff --git a/src/server/database/Database/MySQLConnection.h b/src/server/database/Database/MySQLConnection.h
index 81b57261899..e8f42d49b34 100644
--- a/src/server/database/Database/MySQLConnection.h
+++ b/src/server/database/Database/MySQLConnection.h
@@ -15,18 +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"
-
#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
{
@@ -37,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;
@@ -76,36 +67,29 @@ class TC_DATABASE_API MySQLConnection
bool PrepareStatements();
public:
- bool Execute(const char* sql);
+ bool Execute(char const* sql);
bool Execute(PreparedStatement* stmt);
- ResultSet* Query(const char* sql);
+ ResultSet* Query(char const* sql);
PreparedResultSet* Query(PreparedStatement* stmt);
- bool _Query(const char *sql, MYSQL_RES **pResult, MYSQL_FIELD **pFields, uint64* pRowCount, uint32* pFieldCount);
- bool _Query(PreparedStatement* stmt, MYSQL_RES **pResult, uint64* pRowCount, uint32* pFieldCount);
+ bool _Query(char const* sql, MYSQL_RES** pResult, MYSQL_FIELD** pFields, uint64* pRowCount, uint32* pFieldCount);
+ bool _Query(PreparedStatement* stmt, MYSQL_RES** pResult, uint64* pRowCount, uint32* pFieldCount);
void BeginTransaction();
void RollbackTransaction();
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..3baa7877fe8
--- /dev/null
+++ b/src/server/database/Database/MySQLThreading.cpp
@@ -0,0 +1,32 @@
+/*
+ * 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"
+#ifdef _WIN32 // hack for broken mysql.h not including the correct winsock header for SOCKET definition, fixed in 5.7
+#include <winsock2.h>
+#endif
+#include <mysql.h>
+
+void MySQL::Library_Init()
+{
+ mysql_library_init(-1, nullptr, nullptr);
+}
+
+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..4f8030f6555 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 a46a022df48..137e9c05096 100644
--- a/src/server/database/Database/PreparedStatement.cpp
+++ b/src/server/database/Database/PreparedStatement.cpp
@@ -16,8 +16,15 @@
*/
#include "PreparedStatement.h"
+#include "Errors.h"
#include "MySQLConnection.h"
+#include "QueryResult.h"
#include "Log.h"
+#ifdef _WIN32 // hack for broken mysql.h not including the correct winsock header for SOCKET definition, fixed in 5.7
+#include <winsock2.h>
+#endif
+#include <mysql.h>
+#include <sstream>
PreparedStatement::PreparedStatement(uint32 index, uint8 capacity) :
m_stmt(nullptr), m_index(index), statement_data(capacity) { }
@@ -214,9 +221,9 @@ void MySQLPreparedStatement::ClearParameters()
for (uint32 i=0; i < m_paramCount; ++i)
{
delete m_bind[i].length;
- m_bind[i].length = NULL;
+ m_bind[i].length = nullptr;
delete[] (char*) m_bind[i].buffer;
- m_bind[i].buffer = NULL;
+ m_bind[i].buffer = nullptr;
m_paramsSet[i] = false;
}
}
@@ -227,6 +234,19 @@ static bool ParamenterIndexAssertFail(uint32 stmtIndex, uint8 index, uint32 para
return false;
}
+static void SetParameterValue(MYSQL_BIND* param, enum_field_types type, void const* 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 = nullptr; // Only != NULL for strings
+ param->is_unsigned = isUnsigned;
+
+ memcpy(param->buffer, value, len);
+}
+
//- Bind on mysql level
void MySQLPreparedStatement::AssertValidIndex(uint8 index)
{
@@ -236,6 +256,20 @@ void MySQLPreparedStatement::AssertValidIndex(uint8 index)
TC_LOG_ERROR("sql.sql", "[ERROR] Prepared Statement (id: %u) trying to bind value on already bound index (%u).", m_stmt->m_index, index);
}
+void MySQLPreparedStatement::setNull(const uint8 index)
+{
+ AssertValidIndex(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 = nullptr;
+ param->buffer_length = 0;
+ param->is_null_value = 1;
+ delete param->length;
+ param->length = nullptr;
+}
+
void MySQLPreparedStatement::setBool(const uint8 index, const bool value)
{
setUInt8(index, value ? 1 : 0);
@@ -246,7 +280,7 @@ void MySQLPreparedStatement::setUInt8(const uint8 index, const uint8 value)
AssertValidIndex(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)
@@ -254,7 +288,7 @@ void MySQLPreparedStatement::setUInt16(const uint8 index, const uint16 value)
AssertValidIndex(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)
@@ -262,7 +296,7 @@ void MySQLPreparedStatement::setUInt32(const uint8 index, const uint32 value)
AssertValidIndex(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)
@@ -270,7 +304,7 @@ void MySQLPreparedStatement::setUInt64(const uint8 index, const uint64 value)
AssertValidIndex(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)
@@ -278,7 +312,7 @@ void MySQLPreparedStatement::setInt8(const uint8 index, const int8 value)
AssertValidIndex(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)
@@ -286,7 +320,7 @@ void MySQLPreparedStatement::setInt16(const uint8 index, const int16 value)
AssertValidIndex(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)
@@ -294,7 +328,7 @@ void MySQLPreparedStatement::setInt32(const uint8 index, const int32 value)
AssertValidIndex(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)
@@ -302,7 +336,7 @@ void MySQLPreparedStatement::setInt64(const uint8 index, const int64 value)
AssertValidIndex(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)
@@ -310,7 +344,7 @@ void MySQLPreparedStatement::setFloat(const uint8 index, const float value)
AssertValidIndex(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)
@@ -318,7 +352,7 @@ void MySQLPreparedStatement::setDouble(const uint8 index, const double value)
AssertValidIndex(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)
@@ -328,7 +362,7 @@ void MySQLPreparedStatement::setBinary(const uint8 index, const std::vector<uint
MYSQL_BIND* param = &m_bind[index];
uint32 len = uint32(value.size());
param->buffer_type = MYSQL_TYPE_BLOB;
- delete [] static_cast<char *>(param->buffer);
+ delete [] static_cast<char*>(param->buffer);
param->buffer = new char[len];
param->buffer_length = len;
param->is_null_value = 0;
@@ -343,33 +377,6 @@ void MySQLPreparedStatement::setBinary(const uint8 index, const std::vector<uint
memcpy(param->buffer, value.data(), len);
}
-void MySQLPreparedStatement::setNull(const uint8 index)
-{
- AssertValidIndex(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() const
{
std::string queryString(m_queryString);
@@ -458,7 +465,7 @@ bool PreparedStatementTask::Execute()
if (!result || !result->GetRowCount())
{
delete result;
- m_result->set_value(PreparedQueryResult(NULL));
+ m_result->set_value(PreparedQueryResult(nullptr));
return false;
}
m_result->set_value(PreparedQueryResult(result));
diff --git a/src/server/database/Database/PreparedStatement.h b/src/server/database/Database/PreparedStatement.h
index 33ef04287cd..7d13e81c395 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
@@ -81,6 +83,7 @@ class TC_DATABASE_API PreparedStatement
PreparedStatement(uint32 index, uint8 capacity);
~PreparedStatement();
+ 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);
@@ -94,7 +97,6 @@ class TC_DATABASE_API PreparedStatement
void setDouble(const uint8 index, const double value);
void setString(const uint8 index, const std::string& value);
void setBinary(const uint8 index, const std::vector<uint8>& value);
- void setNull(const uint8 index);
protected:
void BindParameters(MySQLPreparedStatement* stmt);
@@ -147,9 +149,6 @@ class TC_DATABASE_API MySQLPreparedStatement
std::string getQueryString() 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;
@@ -160,9 +159,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 f9c93000da7..ebc1538b5e9 100644
--- a/src/server/database/Database/QueryCallback.h
+++ b/src/server/database/Database/QueryCallback.h
@@ -18,14 +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();
@@ -58,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..7143671db75 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)
@@ -108,12 +47,12 @@ void SQLQueryHolder::SetPreparedResult(size_t index, PreparedResultSet* result)
if (result && !result->GetRowCount())
{
delete result;
- result = NULL;
+ result = nullptr;
}
/// 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..c2c05730ff1 100644
--- a/src/server/database/Database/QueryResult.cpp
+++ b/src/server/database/Database/QueryResult.cpp
@@ -16,8 +16,108 @@
* 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"
+#ifdef _WIN32 // hack for broken mysql.h not including the correct winsock header for SOCKET definition, fixed in 5.7
+#include <winsock2.h>
+#endif
+#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),
@@ -36,11 +136,9 @@ PreparedResultSet::PreparedResultSet(MYSQL_STMT* stmt, MYSQL_RES *result, uint64
m_rowCount(rowCount),
m_rowPosition(0),
m_fieldCount(fieldCount),
-m_rBind(NULL),
+m_rBind(nullptr),
m_stmt(stmt),
-m_metadataResult(result),
-m_isNull(NULL),
-m_length(NULL)
+m_metadataResult(result)
{
if (!m_metadataResult)
return;
@@ -52,8 +150,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,14 +178,14 @@ 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;
m_rBind[i].buffer_length = size;
m_rBind[i].length = &m_length[i];
m_rBind[i].is_null = &m_isNull[i];
- m_rBind[i].error = NULL;
+ m_rBind[i].error = nullptr;
m_rBind[i].is_unsigned = field[i].flags & UNSIGNED_FLAG;
}
@@ -137,7 +239,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 +249,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 +298,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;
}
@@ -227,16 +329,35 @@ void ResultSet::CleanUp()
if (_currentRow)
{
delete [] _currentRow;
- _currentRow = NULL;
+ _currentRow = nullptr;
}
if (_result)
{
mysql_free_result(_result);
- _result = NULL;
+ _result = 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];
+}
+
void PreparedResultSet::CleanUp()
{
if (m_metadataResult)
diff --git a/src/server/database/Database/QueryResult.h b/src/server/database/Database/QueryResult.h
index 2df5d3a4f70..dcfe18765fc 100644
--- a/src/server/database/Database/QueryResult.h
+++ b/src/server/database/Database/QueryResult.h
@@ -19,13 +19,9 @@
#ifndef QUERYRESULT_H
#define QUERYRESULT_H
-#include <memory>
-#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
{
@@ -38,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;
@@ -58,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:
@@ -70,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;
@@ -94,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();
@@ -104,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..4e7e4c8eba5 100644
--- a/src/server/database/Database/SQLOperation.h
+++ b/src/server/database/Database/SQLOperation.h
@@ -18,16 +18,14 @@
#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
{
PreparedStatement* stmt;
- const char* query;
+ char const* query;
};
//- Type specifier of our element data
@@ -56,7 +54,7 @@ class MySQLConnection;
class TC_DATABASE_API SQLOperation
{
public:
- SQLOperation(): m_conn(NULL) { }
+ SQLOperation(): m_conn(nullptr) { }
virtual ~SQLOperation() { }
virtual int call()
diff --git a/src/server/database/Database/Transaction.cpp b/src/server/database/Database/Transaction.cpp
index 52f7062c78a..740e0455881 100644
--- a/src/server/database/Database/Transaction.cpp
+++ b/src/server/database/Database/Transaction.cpp
@@ -15,14 +15,15 @@
* 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;
//- Append a raw ad-hoc query to the transaction
-void Transaction::Append(const char* sql)
+void Transaction::Append(char const* sql)
{
SQLElementData data;
data.type = SQL_ELEMENT_RAW;
@@ -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 6e6d68302f5..33e19531889 100644
--- a/src/server/database/Database/Transaction.h
+++ b/src/server/database/Database/Transaction.h
@@ -18,11 +18,12 @@
#ifndef _TRANSACTION_H
#define _TRANSACTION_H
+#include "Define.h"
+#include "DatabaseEnvFwd.h"
#include "SQLOperation.h"
#include "StringFormat.h"
-
-//- Forward declare (don't include header to prevent circular includes)
-class PreparedStatement;
+#include <mutex>
+#include <vector>
/*! Transactions, high level class. */
class TC_DATABASE_API Transaction
@@ -38,24 +39,23 @@ class TC_DATABASE_API Transaction
~Transaction() { Cleanup(); }
void Append(PreparedStatement* statement);
- void Append(const char* sql);
+ void Append(char const* sql);
template<typename Format, typename... Args>
void PAppend(Format&& sql, Args&&... args)
{
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