aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2019-11-01 16:21:14 +0100
committerShauren <shauren.trinity@gmail.com>2019-11-01 16:21:14 +0100
commitc3a9d56b56b665133707f587ecb1bd1c272f6911 (patch)
tree02dfce1fa605569e3212fbe8804125d55957d7bf /src
parent2072258ef44e89e30256d529686ae2b8dc2b5f0d (diff)
Core/DBLayer: Support using mysql 8
Diffstat (limited to 'src')
-rw-r--r--src/server/database/CMakeLists.txt4
-rw-r--r--src/server/database/Database/DatabaseEnvFwd.h10
-rw-r--r--src/server/database/Database/DatabaseWorkerPool.cpp11
-rw-r--r--src/server/database/Database/Field.cpp7
-rw-r--r--src/server/database/Database/Field.h2
-rw-r--r--src/server/database/Database/Implementation/CharacterDatabase.cpp2
-rw-r--r--src/server/database/Database/Implementation/HotfixDatabase.cpp2
-rw-r--r--src/server/database/Database/Implementation/LoginDatabase.cpp2
-rw-r--r--src/server/database/Database/Implementation/WorldDatabase.cpp2
-rw-r--r--src/server/database/Database/MySQLConnection.cpp41
-rw-r--r--src/server/database/Database/MySQLConnection.h13
-rw-r--r--src/server/database/Database/MySQLHacks.h34
-rw-r--r--src/server/database/Database/MySQLPreparedStatement.cpp274
-rw-r--r--src/server/database/Database/MySQLPreparedStatement.h77
-rw-r--r--src/server/database/Database/MySQLThreading.cpp10
-rw-r--r--src/server/database/Database/MySQLThreading.h1
-rw-r--r--src/server/database/Database/MySQLWorkaround.h21
-rw-r--r--src/server/database/Database/PreparedStatement.cpp258
-rw-r--r--src/server/database/Database/PreparedStatement.h49
-rw-r--r--src/server/database/Database/QueryResult.cpp20
-rw-r--r--src/server/database/Database/QueryResult.h14
-rw-r--r--src/server/scripts/Commands/cs_server.cpp4
22 files changed, 483 insertions, 375 deletions
diff --git a/src/server/database/CMakeLists.txt b/src/server/database/CMakeLists.txt
index f8afa15f3b6..366d3943572 100644
--- a/src/server/database/CMakeLists.txt
+++ b/src/server/database/CMakeLists.txt
@@ -50,9 +50,9 @@ add_definitions(-DTRINITY_API_EXPORT_DATABASE)
target_link_libraries(database
PRIVATE
trinity-core-interface
+ mysql
PUBLIC
- common
- mysql)
+ common)
set_target_properties(database
PROPERTIES
diff --git a/src/server/database/Database/DatabaseEnvFwd.h b/src/server/database/Database/DatabaseEnvFwd.h
index df607b29349..b9dbcfd8322 100644
--- a/src/server/database/Database/DatabaseEnvFwd.h
+++ b/src/server/database/Database/DatabaseEnvFwd.h
@@ -76,10 +76,10 @@ using LoginDatabaseQueryHolder = SQLQueryHolder<LoginDatabaseConnection>;
using WorldDatabaseQueryHolder = SQLQueryHolder<WorldDatabaseConnection>;
// 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;
+struct MySQLHandle;
+struct MySQLResult;
+struct MySQLField;
+struct MySQLBind;
+struct MySQLStmt;
#endif // DatabaseEnvFwd_h__
diff --git a/src/server/database/Database/DatabaseWorkerPool.cpp b/src/server/database/Database/DatabaseWorkerPool.cpp
index dce61ed891b..2f31ae1a5a2 100644
--- a/src/server/database/Database/DatabaseWorkerPool.cpp
+++ b/src/server/database/Database/DatabaseWorkerPool.cpp
@@ -24,6 +24,7 @@
#include "Implementation/CharacterDatabase.h"
#include "Implementation/HotfixDatabase.h"
#include "Log.h"
+#include "MySQLPreparedStatement.h"
#include "PreparedStatement.h"
#include "ProducerConsumerQueue.h"
#include "QueryCallback.h"
@@ -31,10 +32,7 @@
#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 "MySQLWorkaround.h"
#include <mysqld_error.h>
#define MIN_MYSQL_SERVER_VERSION 50100u
@@ -355,7 +353,7 @@ uint32 DatabaseWorkerPool<T>::OpenConnections(InternalIndex type, uint8 numConne
_connections[type].clear();
return error;
}
- else if (mysql_get_server_version(connection->GetHandle()) < MIN_MYSQL_SERVER_VERSION)
+ else if (connection->GetServerVersion() < MIN_MYSQL_SERVER_VERSION)
{
TC_LOG_ERROR("sql.driver", "TrinityCore does not support MySQL versions below 5.1");
return 1;
@@ -376,8 +374,7 @@ unsigned long DatabaseWorkerPool<T>::EscapeString(char *to, const char *from, un
if (!to || !from || !length)
return 0;
- return mysql_real_escape_string(
- _connections[IDX_SYNCH].front()->GetHandle(), to, from, length);
+ return _connections[IDX_SYNCH].front()->EscapeString(to, from, length);
}
template <class T>
diff --git a/src/server/database/Database/Field.cpp b/src/server/database/Database/Field.cpp
index 7847ae3ffd8..1d897820245 100644
--- a/src/server/database/Database/Field.cpp
+++ b/src/server/database/Database/Field.cpp
@@ -299,10 +299,7 @@ void Field::LogWrongType(char* getter) const
getter, meta.Type, meta.TableAlias, meta.Alias, meta.TableName, meta.Name, meta.Index);
}
-#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 "MySQLHacks.h"
static char const* FieldTypeToString(enum_field_types type)
{
@@ -338,7 +335,7 @@ static char const* FieldTypeToString(enum_field_types type)
}
}
-void Field::SetMetadata(MYSQL_FIELD* field, uint32 fieldIndex)
+void Field::SetMetadata(MySQLField* field, uint32 fieldIndex)
{
meta.TableName = field->org_table;
meta.TableAlias = field->table;
diff --git a/src/server/database/Database/Field.h b/src/server/database/Database/Field.h
index 05bafb6a0af..ea035ea4c21 100644
--- a/src/server/database/Database/Field.h
+++ b/src/server/database/Database/Field.h
@@ -138,7 +138,7 @@ class TC_DATABASE_API Field
private:
#ifdef TRINITY_DEBUG
void LogWrongType(char* getter) const;
- void SetMetadata(MYSQL_FIELD* field, uint32 fieldIndex);
+ void SetMetadata(MySQLField* 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 b98f3543044..a5d6692c18e 100644
--- a/src/server/database/Database/Implementation/CharacterDatabase.cpp
+++ b/src/server/database/Database/Implementation/CharacterDatabase.cpp
@@ -16,7 +16,7 @@
*/
#include "CharacterDatabase.h"
-#include "PreparedStatement.h"
+#include "MySQLPreparedStatement.h"
void CharacterDatabaseConnection::DoPrepareStatements()
{
diff --git a/src/server/database/Database/Implementation/HotfixDatabase.cpp b/src/server/database/Database/Implementation/HotfixDatabase.cpp
index 19f9d9235f0..7cd7acdb10e 100644
--- a/src/server/database/Database/Implementation/HotfixDatabase.cpp
+++ b/src/server/database/Database/Implementation/HotfixDatabase.cpp
@@ -19,7 +19,7 @@
// Autogenerated from DB2Structure.h
#include "HotfixDatabase.h"
-#include "PreparedStatement.h"
+#include "MySQLPreparedStatement.h"
// Force locale statments to appear exactly in locale declaration order, right after normal data fetch statement
#define PREPARE_LOCALE_STMT(stmtBase, sql, con) \
diff --git a/src/server/database/Database/Implementation/LoginDatabase.cpp b/src/server/database/Database/Implementation/LoginDatabase.cpp
index 6c7429d37be..e8bd527a984 100644
--- a/src/server/database/Database/Implementation/LoginDatabase.cpp
+++ b/src/server/database/Database/Implementation/LoginDatabase.cpp
@@ -16,7 +16,7 @@
*/
#include "LoginDatabase.h"
-#include "PreparedStatement.h"
+#include "MySQLPreparedStatement.h"
void LoginDatabaseConnection::DoPrepareStatements()
{
diff --git a/src/server/database/Database/Implementation/WorldDatabase.cpp b/src/server/database/Database/Implementation/WorldDatabase.cpp
index f7ee2f1d10d..e2b12403d64 100644
--- a/src/server/database/Database/Implementation/WorldDatabase.cpp
+++ b/src/server/database/Database/Implementation/WorldDatabase.cpp
@@ -16,7 +16,7 @@
*/
#include "WorldDatabase.h"
-#include "PreparedStatement.h"
+#include "MySQLPreparedStatement.h"
void WorldDatabaseConnection::DoPrepareStatements()
{
diff --git a/src/server/database/Database/MySQLConnection.cpp b/src/server/database/Database/MySQLConnection.cpp
index cf953015d19..51d10ddfaf6 100644
--- a/src/server/database/Database/MySQLConnection.cpp
+++ b/src/server/database/Database/MySQLConnection.cpp
@@ -19,16 +19,15 @@
#include "Common.h"
#include "DatabaseWorker.h"
#include "Log.h"
+#include "MySQLHacks.h"
+#include "MySQLPreparedStatement.h"
#include "PreparedStatement.h"
#include "QueryResult.h"
#include "Timer.h"
#include "Transaction.h"
#include "Util.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 <errmsg.h>
-#include <mysql.h>
+#include "MySQLWorkaround.h"
#include <mysqld_error.h>
MySQLConnectionInfo::MySQLConnectionInfo(std::string const& infoString)
@@ -130,8 +129,8 @@ uint32 MySQLConnection::Open()
}
#endif
- m_Mysql = mysql_real_connect(mysqlInit, m_connectionInfo.host.c_str(), m_connectionInfo.user.c_str(),
- m_connectionInfo.password.c_str(), m_connectionInfo.database.c_str(), port, unix_socket, 0);
+ m_Mysql = reinterpret_cast<MySQLHandle*>(mysql_real_connect(mysqlInit, m_connectionInfo.host.c_str(), m_connectionInfo.user.c_str(),
+ m_connectionInfo.password.c_str(), m_connectionInfo.database.c_str(), port, unix_socket, 0));
if (m_Mysql)
{
@@ -241,7 +240,7 @@ bool MySQLConnection::Execute(PreparedStatementBase* stmt)
return true;
}
-bool MySQLConnection::_Query(PreparedStatementBase* stmt, MYSQL_RES** pResult, uint64* pRowCount, uint32* pFieldCount)
+bool MySQLConnection::_Query(PreparedStatementBase* stmt, MySQLResult** pResult, uint64* pRowCount, uint32* pFieldCount)
{
if (!m_Mysql)
return false;
@@ -288,7 +287,7 @@ bool MySQLConnection::_Query(PreparedStatementBase* stmt, MYSQL_RES** pResult, u
m_mStmt->ClearParameters();
- *pResult = mysql_stmt_result_metadata(msql_STMT);
+ *pResult = reinterpret_cast<MySQLResult*>(mysql_stmt_result_metadata(msql_STMT));
*pRowCount = mysql_stmt_num_rows(msql_STMT);
*pFieldCount = mysql_stmt_field_count(msql_STMT);
@@ -300,8 +299,8 @@ ResultSet* MySQLConnection::Query(const char* sql)
if (!sql)
return NULL;
- MYSQL_RES *result = NULL;
- MYSQL_FIELD *fields = NULL;
+ MySQLResult* result = NULL;
+ MySQLField* fields = NULL;
uint64 rowCount = 0;
uint32 fieldCount = 0;
@@ -311,7 +310,7 @@ ResultSet* MySQLConnection::Query(const char* sql)
return new ResultSet(result, fields, rowCount, fieldCount);
}
-bool MySQLConnection::_Query(const char *sql, MYSQL_RES **pResult, MYSQL_FIELD **pFields, uint64* pRowCount, uint32* pFieldCount)
+bool MySQLConnection::_Query(const char* sql, MySQLResult** pResult, MySQLField** pFields, uint64* pRowCount, uint32* pFieldCount)
{
if (!m_Mysql)
return false;
@@ -333,7 +332,7 @@ bool MySQLConnection::_Query(const char *sql, MYSQL_RES **pResult, MYSQL_FIELD *
else
TC_LOG_DEBUG("sql.sql", "[%u ms] SQL: %s", getMSTimeDiff(_s, getMSTime()), sql);
- *pResult = mysql_store_result(m_Mysql);
+ *pResult = reinterpret_cast<MySQLResult*>(mysql_store_result(m_Mysql));
*pRowCount = mysql_affected_rows(m_Mysql);
*pFieldCount = mysql_field_count(m_Mysql);
}
@@ -347,7 +346,7 @@ bool MySQLConnection::_Query(const char *sql, MYSQL_RES **pResult, MYSQL_FIELD *
return false;
}
- *pFields = mysql_fetch_fields(*pResult);
+ *pFields = reinterpret_cast<MySQLField*>(mysql_fetch_fields(*pResult));
return true;
}
@@ -418,6 +417,11 @@ int MySQLConnection::ExecuteTransaction(std::shared_ptr<TransactionBase> transac
return 0;
}
+size_t MySQLConnection::EscapeString(char* to, const char* from, size_t length)
+{
+ return mysql_real_escape_string(m_Mysql, to, from, length);
+}
+
void MySQLConnection::Ping()
{
mysql_ping(m_Mysql);
@@ -438,6 +442,11 @@ void MySQLConnection::Unlock()
m_Mutex.unlock();
}
+uint32 MySQLConnection::GetServerVersion() const
+{
+ return mysql_get_server_version(m_Mysql);
+}
+
MySQLPreparedStatement* MySQLConnection::GetPreparedStatement(uint32 index)
{
ASSERT(index < m_stmts.size());
@@ -477,13 +486,13 @@ void MySQLConnection::PrepareStatement(uint32 index, std::string const& sql, Con
m_prepareError = true;
}
else
- m_stmts[index] = Trinity::make_unique<MySQLPreparedStatement>(stmt, sql);
+ m_stmts[index] = Trinity::make_unique<MySQLPreparedStatement>(reinterpret_cast<MySQLStmt*>(stmt), sql);
}
}
PreparedResultSet* MySQLConnection::Query(PreparedStatementBase* stmt)
{
- MYSQL_RES *result = NULL;
+ MySQLResult* result = NULL;
uint64 rowCount = 0;
uint32 fieldCount = 0;
@@ -509,7 +518,7 @@ bool MySQLConnection::_HandleMySQLErrno(uint32 errNo, uint8 attempts /*= 5*/)
{
TC_LOG_ERROR("sql.sql", "Lost the connection to the MySQL server!");
- mysql_close(GetHandle());
+ mysql_close(m_Mysql);
m_Mysql = nullptr;
}
diff --git a/src/server/database/Database/MySQLConnection.h b/src/server/database/Database/MySQLConnection.h
index ea9ce7eb46f..0340d7e62c4 100644
--- a/src/server/database/Database/MySQLConnection.h
+++ b/src/server/database/Database/MySQLConnection.h
@@ -66,19 +66,18 @@ class TC_DATABASE_API MySQLConnection
bool PrepareStatements();
- public:
bool Execute(const char* sql);
bool Execute(PreparedStatementBase* stmt);
ResultSet* Query(const char* sql);
PreparedResultSet* Query(PreparedStatementBase* stmt);
- bool _Query(const char *sql, MYSQL_RES **pResult, MYSQL_FIELD **pFields, uint64* pRowCount, uint32* pFieldCount);
- bool _Query(PreparedStatementBase* stmt, MYSQL_RES **pResult, uint64* pRowCount, uint32* pFieldCount);
+ bool _Query(const char* sql, MySQLResult** pResult, MySQLField** pFields, uint64* pRowCount, uint32* pFieldCount);
+ bool _Query(PreparedStatementBase* stmt, MySQLResult** pResult, uint64* pRowCount, uint32* pFieldCount);
void BeginTransaction();
void RollbackTransaction();
void CommitTransaction();
int ExecuteTransaction(std::shared_ptr<TransactionBase> transaction);
-
+ size_t EscapeString(char* to, const char* from, size_t length);
void Ping();
uint32 GetLastError();
@@ -91,13 +90,12 @@ class TC_DATABASE_API MySQLConnection
/// Called by parent databasepool. Will let other threads access this connection
void Unlock();
- MYSQL* GetHandle() { return m_Mysql; }
+ uint32 GetServerVersion() const;
MySQLPreparedStatement* GetPreparedStatement(uint32 index);
void PrepareStatement(uint32 index, std::string const& sql, ConnectionFlags flags);
virtual void DoPrepareStatements() = 0;
- protected:
typedef std::vector<std::unique_ptr<MySQLPreparedStatement>> PreparedStatementContainer;
PreparedStatementContainer m_stmts; //! PreparedStatements storage
@@ -107,10 +105,9 @@ class TC_DATABASE_API MySQLConnection
private:
bool _HandleMySQLErrno(uint32 errNo, uint8 attempts = 5);
- private:
ProducerConsumerQueue<SQLOperation*>* m_queue; //! Queue shared with other asynchronous connections.
std::unique_ptr<DatabaseWorker> m_worker; //! Core worker task.
- MYSQL* m_Mysql; //! MySQL Handle.
+ MySQLHandle* m_Mysql; //! MySQL Handle.
MySQLConnectionInfo& m_connectionInfo; //! Connection info (used for logging)
ConnectionFlags m_connectionFlags; //! Connection flags (for preparing relevant statements)
std::mutex m_Mutex;
diff --git a/src/server/database/Database/MySQLHacks.h b/src/server/database/Database/MySQLHacks.h
new file mode 100644
index 00000000000..0967342dc88
--- /dev/null
+++ b/src/server/database/Database/MySQLHacks.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2008-2019 TrinityCore <https://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 MySQLHacks_h__
+#define MySQLHacks_h__
+
+#include "MySQLWorkaround.h"
+#include <type_traits>
+
+struct MySQLHandle : MYSQL { };
+struct MySQLResult : MYSQL_RES { };
+struct MySQLField : MYSQL_FIELD { };
+struct MySQLBind : MYSQL_BIND { };
+struct MySQLStmt : MYSQL_STMT { };
+
+// mysql 8 removed my_bool typedef (it was char) and started using bools directly
+// to maintain compatibility we use this trick to retrieve which type is being used
+using MySQLBool = std::remove_pointer_t<decltype(std::declval<MYSQL_BIND>().is_null)>;
+
+#endif // MySQLHacks_h__
diff --git a/src/server/database/Database/MySQLPreparedStatement.cpp b/src/server/database/Database/MySQLPreparedStatement.cpp
new file mode 100644
index 00000000000..b8aeab7a32d
--- /dev/null
+++ b/src/server/database/Database/MySQLPreparedStatement.cpp
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2008-2019 TrinityCore <https://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 "MySQLPreparedStatement.h"
+#include "Errors.h"
+#include "Log.h"
+#include "MySQLHacks.h"
+#include "PreparedStatement.h"
+#include <sstream>
+
+MySQLPreparedStatement::MySQLPreparedStatement(MySQLStmt* stmt, std::string queryString) :
+ m_stmt(nullptr), m_Mstmt(stmt), m_bind(nullptr), m_queryString(std::move(queryString))
+{
+ /// Initialize variable parameters
+ m_paramCount = mysql_stmt_param_count(stmt);
+ m_paramsSet.assign(m_paramCount, false);
+ m_bind = new MySQLBind[m_paramCount];
+ memset(m_bind, 0, sizeof(MySQLBind) * m_paramCount);
+
+ /// "If set to 1, causes mysql_stmt_store_result() to update the metadata MYSQL_FIELD->max_length value."
+ MySQLBool bool_tmp = MySQLBool(1);
+ mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, &bool_tmp);
+}
+
+MySQLPreparedStatement::~MySQLPreparedStatement()
+{
+ ClearParameters();
+ if (m_Mstmt->bind_result_done)
+ {
+ delete[] m_Mstmt->bind->length;
+ delete[] m_Mstmt->bind->is_null;
+ }
+ mysql_stmt_close(m_Mstmt);
+ delete[] m_bind;
+}
+
+void MySQLPreparedStatement::ClearParameters()
+{
+ for (uint32 i=0; i < m_paramCount; ++i)
+ {
+ delete m_bind[i].length;
+ m_bind[i].length = NULL;
+ delete[] (char*) m_bind[i].buffer;
+ m_bind[i].buffer = NULL;
+ m_paramsSet[i] = false;
+ }
+}
+
+static bool ParamenterIndexAssertFail(uint32 stmtIndex, uint8 index, uint32 paramCount)
+{
+ TC_LOG_ERROR("sql.driver", "Attempted to bind parameter %u%s on a PreparedStatement %u (statement has only %u parameters)", uint32(index) + 1, (index == 1 ? "st" : (index == 2 ? "nd" : (index == 3 ? "rd" : "nd"))), stmtIndex, paramCount);
+ return false;
+}
+
+static void SetParameterValue(MYSQL_BIND* param, enum_field_types type, const void* value, uint32 len, bool isUnsigned)
+{
+ param->buffer_type = type;
+ delete[] static_cast<char *>(param->buffer);
+ param->buffer = new char[len];
+ param->buffer_length = 0;
+ param->is_null_value = 0;
+ param->length = NULL; // Only != NULL for strings
+ param->is_unsigned = isUnsigned;
+
+ memcpy(param->buffer, value, len);
+}
+
+//- Bind on mysql level
+void MySQLPreparedStatement::AssertValidIndex(uint8 index)
+{
+ ASSERT(index < m_paramCount || ParamenterIndexAssertFail(m_stmt->m_index, index, m_paramCount));
+
+ if (m_paramsSet[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 = NULL;
+ param->buffer_length = 0;
+ param->is_null_value = 1;
+ delete param->length;
+ param->length = NULL;
+}
+
+void MySQLPreparedStatement::setBool(const uint8 index, const bool value)
+{
+ setUInt8(index, value ? 1 : 0);
+}
+
+void MySQLPreparedStatement::setUInt8(const uint8 index, const uint8 value)
+{
+ AssertValidIndex(index);
+ m_paramsSet[index] = true;
+ MYSQL_BIND* param = &m_bind[index];
+ SetParameterValue(param, MYSQL_TYPE_TINY, &value, sizeof(uint8), true);
+}
+
+void MySQLPreparedStatement::setUInt16(const uint8 index, const uint16 value)
+{
+ AssertValidIndex(index);
+ m_paramsSet[index] = true;
+ MYSQL_BIND* param = &m_bind[index];
+ SetParameterValue(param, MYSQL_TYPE_SHORT, &value, sizeof(uint16), true);
+}
+
+void MySQLPreparedStatement::setUInt32(const uint8 index, const uint32 value)
+{
+ AssertValidIndex(index);
+ m_paramsSet[index] = true;
+ MYSQL_BIND* param = &m_bind[index];
+ SetParameterValue(param, MYSQL_TYPE_LONG, &value, sizeof(uint32), true);
+}
+
+void MySQLPreparedStatement::setUInt64(const uint8 index, const uint64 value)
+{
+ AssertValidIndex(index);
+ m_paramsSet[index] = true;
+ MYSQL_BIND* param = &m_bind[index];
+ SetParameterValue(param, MYSQL_TYPE_LONGLONG, &value, sizeof(uint64), true);
+}
+
+void MySQLPreparedStatement::setInt8(const uint8 index, const int8 value)
+{
+ AssertValidIndex(index);
+ m_paramsSet[index] = true;
+ MYSQL_BIND* param = &m_bind[index];
+ SetParameterValue(param, MYSQL_TYPE_TINY, &value, sizeof(int8), false);
+}
+
+void MySQLPreparedStatement::setInt16(const uint8 index, const int16 value)
+{
+ AssertValidIndex(index);
+ m_paramsSet[index] = true;
+ MYSQL_BIND* param = &m_bind[index];
+ SetParameterValue(param, MYSQL_TYPE_SHORT, &value, sizeof(int16), false);
+}
+
+void MySQLPreparedStatement::setInt32(const uint8 index, const int32 value)
+{
+ AssertValidIndex(index);
+ m_paramsSet[index] = true;
+ MYSQL_BIND* param = &m_bind[index];
+ SetParameterValue(param, MYSQL_TYPE_LONG, &value, sizeof(int32), false);
+}
+
+void MySQLPreparedStatement::setInt64(const uint8 index, const int64 value)
+{
+ AssertValidIndex(index);
+ m_paramsSet[index] = true;
+ MYSQL_BIND* param = &m_bind[index];
+ SetParameterValue(param, MYSQL_TYPE_LONGLONG, &value, sizeof(int64), false);
+}
+
+void MySQLPreparedStatement::setFloat(const uint8 index, const float value)
+{
+ AssertValidIndex(index);
+ m_paramsSet[index] = true;
+ MYSQL_BIND* param = &m_bind[index];
+ SetParameterValue(param, MYSQL_TYPE_FLOAT, &value, sizeof(float), (value > 0.0f));
+}
+
+void MySQLPreparedStatement::setDouble(const uint8 index, const double value)
+{
+ AssertValidIndex(index);
+ m_paramsSet[index] = true;
+ MYSQL_BIND* param = &m_bind[index];
+ SetParameterValue(param, MYSQL_TYPE_DOUBLE, &value, sizeof(double), (value > 0.0f));
+}
+
+void MySQLPreparedStatement::setBinary(const uint8 index, const std::vector<uint8>& value, bool isString)
+{
+ AssertValidIndex(index);
+ m_paramsSet[index] = true;
+ MYSQL_BIND* param = &m_bind[index];
+ uint32 len = uint32(value.size());
+ param->buffer_type = MYSQL_TYPE_BLOB;
+ delete [] static_cast<char *>(param->buffer);
+ param->buffer = new char[len];
+ param->buffer_length = len;
+ param->is_null_value = 0;
+ delete param->length;
+ param->length = new unsigned long(len);
+ if (isString)
+ {
+ *param->length -= 1;
+ param->buffer_type = MYSQL_TYPE_VAR_STRING;
+ }
+
+ memcpy(param->buffer, value.data(), len);
+}
+
+std::string MySQLPreparedStatement::getQueryString() const
+{
+ std::string queryString(m_queryString);
+
+ size_t pos = 0;
+ for (uint32 i = 0; i < m_stmt->statement_data.size(); i++)
+ {
+ pos = queryString.find('?', pos);
+ std::stringstream ss;
+
+ switch (m_stmt->statement_data[i].type)
+ {
+ case TYPE_BOOL:
+ ss << uint16(m_stmt->statement_data[i].data.boolean);
+ break;
+ case TYPE_UI8:
+ ss << uint16(m_stmt->statement_data[i].data.ui8); // stringstream will append a character with that code instead of numeric representation
+ break;
+ case TYPE_UI16:
+ ss << m_stmt->statement_data[i].data.ui16;
+ break;
+ case TYPE_UI32:
+ ss << m_stmt->statement_data[i].data.ui32;
+ break;
+ case TYPE_I8:
+ ss << int16(m_stmt->statement_data[i].data.i8); // stringstream will append a character with that code instead of numeric representation
+ break;
+ case TYPE_I16:
+ ss << m_stmt->statement_data[i].data.i16;
+ break;
+ case TYPE_I32:
+ ss << m_stmt->statement_data[i].data.i32;
+ break;
+ case TYPE_UI64:
+ ss << m_stmt->statement_data[i].data.ui64;
+ break;
+ case TYPE_I64:
+ ss << m_stmt->statement_data[i].data.i64;
+ break;
+ case TYPE_FLOAT:
+ ss << m_stmt->statement_data[i].data.f;
+ break;
+ case TYPE_DOUBLE:
+ ss << m_stmt->statement_data[i].data.d;
+ break;
+ case TYPE_STRING:
+ ss << '\'' << (char const*)m_stmt->statement_data[i].binary.data() << '\'';
+ break;
+ case TYPE_BINARY:
+ ss << "BINARY";
+ break;
+ case TYPE_NULL:
+ ss << "NULL";
+ break;
+ }
+
+ std::string replaceStr = ss.str();
+ queryString.replace(pos, 1, replaceStr);
+ pos += replaceStr.length();
+ }
+
+ return queryString;
+}
diff --git a/src/server/database/Database/MySQLPreparedStatement.h b/src/server/database/Database/MySQLPreparedStatement.h
new file mode 100644
index 00000000000..56b19947c62
--- /dev/null
+++ b/src/server/database/Database/MySQLPreparedStatement.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2008-2019 TrinityCore <https://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 MySQLPreparedStatement_h__
+#define MySQLPreparedStatement_h__
+
+#include "DatabaseEnvFwd.h"
+#include "Define.h"
+#include "MySQLWorkaround.h"
+#include <string>
+#include <vector>
+
+class MySQLConnection;
+class PreparedStatementBase;
+
+//- Class of which the instances are unique per MySQLConnection
+//- access to these class objects is only done when a prepared statement task
+//- is executed.
+class TC_DATABASE_API MySQLPreparedStatement
+{
+ friend class MySQLConnection;
+ friend class PreparedStatementBase;
+
+ public:
+ MySQLPreparedStatement(MySQLStmt* stmt, std::string queryString);
+ ~MySQLPreparedStatement();
+
+ void setNull(const uint8 index);
+ void setBool(const uint8 index, const bool value);
+ void setUInt8(const uint8 index, const uint8 value);
+ void setUInt16(const uint8 index, const uint16 value);
+ void setUInt32(const uint8 index, const uint32 value);
+ void setUInt64(const uint8 index, const uint64 value);
+ void setInt8(const uint8 index, const int8 value);
+ void setInt16(const uint8 index, const int16 value);
+ void setInt32(const uint8 index, const int32 value);
+ void setInt64(const uint8 index, const int64 value);
+ void setFloat(const uint8 index, const float value);
+ void setDouble(const uint8 index, const double value);
+ void setBinary(const uint8 index, const std::vector<uint8>& value, bool isString);
+
+ uint32 GetParameterCount() const { return m_paramCount; }
+
+ protected:
+ MySQLStmt* GetSTMT() { return m_Mstmt; }
+ MySQLBind* GetBind() { return m_bind; }
+ PreparedStatementBase* m_stmt;
+ void ClearParameters();
+ void AssertValidIndex(uint8 index);
+ std::string getQueryString() const;
+
+ private:
+ MySQLStmt* m_Mstmt;
+ uint32 m_paramCount;
+ std::vector<bool> m_paramsSet;
+ MySQLBind* m_bind;
+ std::string const m_queryString;
+
+ MySQLPreparedStatement(MySQLPreparedStatement const& right) = delete;
+ MySQLPreparedStatement& operator=(MySQLPreparedStatement const& right) = delete;
+};
+
+#endif // MySQLPreparedStatement_h__
diff --git a/src/server/database/Database/MySQLThreading.cpp b/src/server/database/Database/MySQLThreading.cpp
index eccfdfeb6c5..4ce39389eab 100644
--- a/src/server/database/Database/MySQLThreading.cpp
+++ b/src/server/database/Database/MySQLThreading.cpp
@@ -16,10 +16,7 @@
*/
#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>
+#include "MySQLWorkaround.h"
void MySQL::Library_Init()
{
@@ -30,3 +27,8 @@ void MySQL::Library_End()
{
mysql_library_end();
}
+
+char const* TC_DATABASE_API MySQL::GetLibraryVersion()
+{
+ return MYSQL_SERVER_VERSION;
+}
diff --git a/src/server/database/Database/MySQLThreading.h b/src/server/database/Database/MySQLThreading.h
index 6ab52625601..6d4217cacc8 100644
--- a/src/server/database/Database/MySQLThreading.h
+++ b/src/server/database/Database/MySQLThreading.h
@@ -24,6 +24,7 @@ namespace MySQL
{
void TC_DATABASE_API Library_Init();
void TC_DATABASE_API Library_End();
+ char const* TC_DATABASE_API GetLibraryVersion();
};
#endif
diff --git a/src/server/database/Database/MySQLWorkaround.h b/src/server/database/Database/MySQLWorkaround.h
new file mode 100644
index 00000000000..79aef08b954
--- /dev/null
+++ b/src/server/database/Database/MySQLWorkaround.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2008-2019 TrinityCore <https://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/>.
+ */
+
+#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>
diff --git a/src/server/database/Database/PreparedStatement.cpp b/src/server/database/Database/PreparedStatement.cpp
index e410df84464..c74d675cca1 100644
--- a/src/server/database/Database/PreparedStatement.cpp
+++ b/src/server/database/Database/PreparedStatement.cpp
@@ -18,13 +18,10 @@
#include "PreparedStatement.h"
#include "Errors.h"
#include "MySQLConnection.h"
+#include "MySQLPreparedStatement.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>
+#include "MySQLWorkaround.h"
PreparedStatementBase::PreparedStatementBase(uint32 index, uint8 capacity) :
m_stmt(nullptr), m_index(index), statement_data(capacity) { }
@@ -204,257 +201,6 @@ void PreparedStatementBase::setNull(const uint8 index)
statement_data[index].type = TYPE_NULL;
}
-MySQLPreparedStatement::MySQLPreparedStatement(MYSQL_STMT* stmt, std::string queryString) :
- m_stmt(nullptr), m_Mstmt(stmt), m_bind(nullptr), m_queryString(std::move(queryString))
-{
- /// Initialize variable parameters
- m_paramCount = mysql_stmt_param_count(stmt);
- m_paramsSet.assign(m_paramCount, false);
- m_bind = new MYSQL_BIND[m_paramCount];
- memset(m_bind, 0, sizeof(MYSQL_BIND)*m_paramCount);
-
- /// "If set to 1, causes mysql_stmt_store_result() to update the metadata MYSQL_FIELD->max_length value."
- my_bool bool_tmp = 1;
- mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, &bool_tmp);
-}
-
-MySQLPreparedStatement::~MySQLPreparedStatement()
-{
- ClearParameters();
- if (m_Mstmt->bind_result_done)
- {
- delete[] m_Mstmt->bind->length;
- delete[] m_Mstmt->bind->is_null;
- }
- mysql_stmt_close(m_Mstmt);
- delete[] m_bind;
-}
-
-void MySQLPreparedStatement::ClearParameters()
-{
- for (uint32 i=0; i < m_paramCount; ++i)
- {
- delete m_bind[i].length;
- m_bind[i].length = NULL;
- delete[] (char*) m_bind[i].buffer;
- m_bind[i].buffer = NULL;
- m_paramsSet[i] = false;
- }
-}
-
-static bool ParamenterIndexAssertFail(uint32 stmtIndex, uint8 index, uint32 paramCount)
-{
- TC_LOG_ERROR("sql.driver", "Attempted to bind parameter %u%s on a PreparedStatement %u (statement has only %u parameters)", uint32(index) + 1, (index == 1 ? "st" : (index == 2 ? "nd" : (index == 3 ? "rd" : "nd"))), stmtIndex, paramCount);
- return false;
-}
-
-static void SetParameterValue(MYSQL_BIND* param, enum_field_types type, const void* value, uint32 len, bool isUnsigned)
-{
- param->buffer_type = type;
- delete[] static_cast<char *>(param->buffer);
- param->buffer = new char[len];
- param->buffer_length = 0;
- param->is_null_value = 0;
- param->length = NULL; // Only != NULL for strings
- param->is_unsigned = isUnsigned;
-
- memcpy(param->buffer, value, len);
-}
-
-//- Bind on mysql level
-void MySQLPreparedStatement::AssertValidIndex(uint8 index)
-{
- ASSERT(index < m_paramCount || ParamenterIndexAssertFail(m_stmt->m_index, index, m_paramCount));
-
- if (m_paramsSet[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 = NULL;
- param->buffer_length = 0;
- param->is_null_value = 1;
- delete param->length;
- param->length = NULL;
-}
-
-void MySQLPreparedStatement::setBool(const uint8 index, const bool value)
-{
- setUInt8(index, value ? 1 : 0);
-}
-
-void MySQLPreparedStatement::setUInt8(const uint8 index, const uint8 value)
-{
- AssertValidIndex(index);
- m_paramsSet[index] = true;
- MYSQL_BIND* param = &m_bind[index];
- SetParameterValue(param, MYSQL_TYPE_TINY, &value, sizeof(uint8), true);
-}
-
-void MySQLPreparedStatement::setUInt16(const uint8 index, const uint16 value)
-{
- AssertValidIndex(index);
- m_paramsSet[index] = true;
- MYSQL_BIND* param = &m_bind[index];
- SetParameterValue(param, MYSQL_TYPE_SHORT, &value, sizeof(uint16), true);
-}
-
-void MySQLPreparedStatement::setUInt32(const uint8 index, const uint32 value)
-{
- AssertValidIndex(index);
- m_paramsSet[index] = true;
- MYSQL_BIND* param = &m_bind[index];
- SetParameterValue(param, MYSQL_TYPE_LONG, &value, sizeof(uint32), true);
-}
-
-void MySQLPreparedStatement::setUInt64(const uint8 index, const uint64 value)
-{
- AssertValidIndex(index);
- m_paramsSet[index] = true;
- MYSQL_BIND* param = &m_bind[index];
- SetParameterValue(param, MYSQL_TYPE_LONGLONG, &value, sizeof(uint64), true);
-}
-
-void MySQLPreparedStatement::setInt8(const uint8 index, const int8 value)
-{
- AssertValidIndex(index);
- m_paramsSet[index] = true;
- MYSQL_BIND* param = &m_bind[index];
- SetParameterValue(param, MYSQL_TYPE_TINY, &value, sizeof(int8), false);
-}
-
-void MySQLPreparedStatement::setInt16(const uint8 index, const int16 value)
-{
- AssertValidIndex(index);
- m_paramsSet[index] = true;
- MYSQL_BIND* param = &m_bind[index];
- SetParameterValue(param, MYSQL_TYPE_SHORT, &value, sizeof(int16), false);
-}
-
-void MySQLPreparedStatement::setInt32(const uint8 index, const int32 value)
-{
- AssertValidIndex(index);
- m_paramsSet[index] = true;
- MYSQL_BIND* param = &m_bind[index];
- SetParameterValue(param, MYSQL_TYPE_LONG, &value, sizeof(int32), false);
-}
-
-void MySQLPreparedStatement::setInt64(const uint8 index, const int64 value)
-{
- AssertValidIndex(index);
- m_paramsSet[index] = true;
- MYSQL_BIND* param = &m_bind[index];
- SetParameterValue(param, MYSQL_TYPE_LONGLONG, &value, sizeof(int64), false);
-}
-
-void MySQLPreparedStatement::setFloat(const uint8 index, const float value)
-{
- AssertValidIndex(index);
- m_paramsSet[index] = true;
- MYSQL_BIND* param = &m_bind[index];
- SetParameterValue(param, MYSQL_TYPE_FLOAT, &value, sizeof(float), (value > 0.0f));
-}
-
-void MySQLPreparedStatement::setDouble(const uint8 index, const double value)
-{
- AssertValidIndex(index);
- m_paramsSet[index] = true;
- MYSQL_BIND* param = &m_bind[index];
- SetParameterValue(param, MYSQL_TYPE_DOUBLE, &value, sizeof(double), (value > 0.0f));
-}
-
-void MySQLPreparedStatement::setBinary(const uint8 index, const std::vector<uint8>& value, bool isString)
-{
- AssertValidIndex(index);
- m_paramsSet[index] = true;
- MYSQL_BIND* param = &m_bind[index];
- uint32 len = uint32(value.size());
- param->buffer_type = MYSQL_TYPE_BLOB;
- delete [] static_cast<char *>(param->buffer);
- param->buffer = new char[len];
- param->buffer_length = len;
- param->is_null_value = 0;
- delete param->length;
- param->length = new unsigned long(len);
- if (isString)
- {
- *param->length -= 1;
- param->buffer_type = MYSQL_TYPE_VAR_STRING;
- }
-
- memcpy(param->buffer, value.data(), len);
-}
-
-std::string MySQLPreparedStatement::getQueryString() const
-{
- std::string queryString(m_queryString);
-
- size_t pos = 0;
- for (uint32 i = 0; i < m_stmt->statement_data.size(); i++)
- {
- pos = queryString.find('?', pos);
- std::stringstream ss;
-
- switch (m_stmt->statement_data[i].type)
- {
- case TYPE_BOOL:
- ss << uint16(m_stmt->statement_data[i].data.boolean);
- break;
- case TYPE_UI8:
- ss << uint16(m_stmt->statement_data[i].data.ui8); // stringstream will append a character with that code instead of numeric representation
- break;
- case TYPE_UI16:
- ss << m_stmt->statement_data[i].data.ui16;
- break;
- case TYPE_UI32:
- ss << m_stmt->statement_data[i].data.ui32;
- break;
- case TYPE_I8:
- ss << int16(m_stmt->statement_data[i].data.i8); // stringstream will append a character with that code instead of numeric representation
- break;
- case TYPE_I16:
- ss << m_stmt->statement_data[i].data.i16;
- break;
- case TYPE_I32:
- ss << m_stmt->statement_data[i].data.i32;
- break;
- case TYPE_UI64:
- ss << m_stmt->statement_data[i].data.ui64;
- break;
- case TYPE_I64:
- ss << m_stmt->statement_data[i].data.i64;
- break;
- case TYPE_FLOAT:
- ss << m_stmt->statement_data[i].data.f;
- break;
- case TYPE_DOUBLE:
- ss << m_stmt->statement_data[i].data.d;
- break;
- case TYPE_STRING:
- ss << '\'' << (char const*)m_stmt->statement_data[i].binary.data() << '\'';
- break;
- case TYPE_BINARY:
- ss << "BINARY";
- break;
- case TYPE_NULL:
- ss << "NULL";
- break;
- }
-
- std::string replaceStr = ss.str();
- queryString.replace(pos, 1, replaceStr);
- pos += replaceStr.length();
- }
-
- return queryString;
-}
-
//- Execution
PreparedStatementTask::PreparedStatementTask(PreparedStatementBase* stmt, bool async) :
m_stmt(stmt), m_result(nullptr)
diff --git a/src/server/database/Database/PreparedStatement.h b/src/server/database/Database/PreparedStatement.h
index 3495c5aee67..1a6ff2b4c5f 100644
--- a/src/server/database/Database/PreparedStatement.h
+++ b/src/server/database/Database/PreparedStatement.h
@@ -98,6 +98,8 @@ class TC_DATABASE_API PreparedStatementBase
void setBinary(const uint8 index, const std::vector<uint8>& value);
void setNull(const uint8 index);
+ uint32 GetIndex() const { return m_index; }
+
protected:
void BindParameters(MySQLPreparedStatement* stmt);
@@ -125,53 +127,6 @@ private:
PreparedStatement& operator=(PreparedStatement const& right) = delete;
};
-//- Class of which the instances are unique per MySQLConnection
-//- access to these class objects is only done when a prepared statement task
-//- is executed.
-class TC_DATABASE_API MySQLPreparedStatement
-{
- friend class MySQLConnection;
- friend class PreparedStatementBase;
-
- public:
- MySQLPreparedStatement(MYSQL_STMT* stmt, std::string queryString);
- ~MySQLPreparedStatement();
-
- void setNull(const uint8 index);
- void setBool(const uint8 index, const bool value);
- void setUInt8(const uint8 index, const uint8 value);
- void setUInt16(const uint8 index, const uint16 value);
- void setUInt32(const uint8 index, const uint32 value);
- void setUInt64(const uint8 index, const uint64 value);
- void setInt8(const uint8 index, const int8 value);
- void setInt16(const uint8 index, const int16 value);
- void setInt32(const uint8 index, const int32 value);
- void setInt64(const uint8 index, const int64 value);
- void setFloat(const uint8 index, const float value);
- void setDouble(const uint8 index, const double value);
- void setBinary(const uint8 index, const std::vector<uint8>& value, bool isString);
-
- uint32 GetParameterCount() const { return m_paramCount; }
-
- protected:
- MYSQL_STMT* GetSTMT() { return m_Mstmt; }
- MYSQL_BIND* GetBind() { return m_bind; }
- PreparedStatementBase* m_stmt;
- void ClearParameters();
- void AssertValidIndex(uint8 index);
- std::string getQueryString() const;
-
- private:
- MYSQL_STMT* m_Mstmt;
- uint32 m_paramCount;
- std::vector<bool> m_paramsSet;
- MYSQL_BIND* m_bind;
- std::string const m_queryString;
-
- MySQLPreparedStatement(MySQLPreparedStatement const& right) = delete;
- MySQLPreparedStatement& operator=(MySQLPreparedStatement const& right) = delete;
-};
-
//- Lower-level class, enqueuable operation
class TC_DATABASE_API PreparedStatementTask : public SQLOperation
{
diff --git a/src/server/database/Database/QueryResult.cpp b/src/server/database/Database/QueryResult.cpp
index 0e76a7807a4..4f381f8449b 100644
--- a/src/server/database/Database/QueryResult.cpp
+++ b/src/server/database/Database/QueryResult.cpp
@@ -20,10 +20,8 @@
#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>
+#include "MySQLHacks.h"
+#include "MySQLWorkaround.h"
static uint32 SizeForType(MYSQL_FIELD* field)
{
@@ -119,7 +117,7 @@ DatabaseFieldTypes MysqlTypeToFieldType(enum_field_types type)
return DatabaseFieldTypes::Null;
}
-ResultSet::ResultSet(MYSQL_RES *result, MYSQL_FIELD *fields, uint64 rowCount, uint32 fieldCount) :
+ResultSet::ResultSet(MySQLResult* result, MySQLField* fields, uint64 rowCount, uint32 fieldCount) :
_rowCount(rowCount),
_fieldCount(fieldCount),
_result(result),
@@ -132,7 +130,7 @@ _fields(fields)
#endif
}
-PreparedResultSet::PreparedResultSet(MYSQL_STMT* stmt, MYSQL_RES *result, uint64 rowCount, uint32 fieldCount) :
+PreparedResultSet::PreparedResultSet(MySQLStmt* stmt, MySQLResult* result, uint64 rowCount, uint32 fieldCount) :
m_rowCount(rowCount),
m_rowPosition(0),
m_fieldCount(fieldCount),
@@ -149,16 +147,16 @@ m_metadataResult(result)
delete[] m_stmt->bind->is_null;
}
- m_rBind = new MYSQL_BIND[m_fieldCount];
+ m_rBind = new MySQLBind[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];
+ MySQLBool* m_isNull = new MySQLBool[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);
+ memset(m_isNull, 0, sizeof(MySQLBool) * m_fieldCount);
+ memset(m_rBind, 0, sizeof(MySQLBind) * m_fieldCount);
memset(m_length, 0, sizeof(unsigned long) * m_fieldCount);
//- This is where we store the (entire) resultset
@@ -174,7 +172,7 @@ m_metadataResult(result)
m_rowCount = mysql_stmt_num_rows(m_stmt);
//- This is where we prepare the buffer based on metadata
- MYSQL_FIELD* field = mysql_fetch_fields(m_metadataResult);
+ MySQLField* field = reinterpret_cast<MySQLField*>(mysql_fetch_fields(m_metadataResult));
std::size_t rowSize = 0;
for (uint32 i = 0; i < m_fieldCount; ++i)
{
diff --git a/src/server/database/Database/QueryResult.h b/src/server/database/Database/QueryResult.h
index 230944135f6..3e193341937 100644
--- a/src/server/database/Database/QueryResult.h
+++ b/src/server/database/Database/QueryResult.h
@@ -26,7 +26,7 @@
class TC_DATABASE_API ResultSet
{
public:
- ResultSet(MYSQL_RES* result, MYSQL_FIELD* fields, uint64 rowCount, uint32 fieldCount);
+ ResultSet(MySQLResult* result, MySQLField* fields, uint64 rowCount, uint32 fieldCount);
~ResultSet();
bool NextRow();
@@ -43,8 +43,8 @@ class TC_DATABASE_API ResultSet
private:
void CleanUp();
- MYSQL_RES* _result;
- MYSQL_FIELD* _fields;
+ MySQLResult* _result;
+ MySQLField* _fields;
ResultSet(ResultSet const& right) = delete;
ResultSet& operator=(ResultSet const& right) = delete;
@@ -53,7 +53,7 @@ class TC_DATABASE_API ResultSet
class TC_DATABASE_API PreparedResultSet
{
public:
- PreparedResultSet(MYSQL_STMT* stmt, MYSQL_RES* result, uint64 rowCount, uint32 fieldCount);
+ PreparedResultSet(MySQLStmt* stmt, MySQLResult* result, uint64 rowCount, uint32 fieldCount);
~PreparedResultSet();
bool NextRow();
@@ -70,9 +70,9 @@ class TC_DATABASE_API PreparedResultSet
uint32 m_fieldCount;
private:
- MYSQL_BIND* m_rBind;
- MYSQL_STMT* m_stmt;
- MYSQL_RES* m_metadataResult; ///< Field metadata, returned by mysql_stmt_result_metadata
+ MySQLBind* m_rBind;
+ MySQLStmt* m_stmt;
+ MySQLResult* m_metadataResult; ///< Field metadata, returned by mysql_stmt_result_metadata
void CleanUp();
bool _NextRow();
diff --git a/src/server/scripts/Commands/cs_server.cpp b/src/server/scripts/Commands/cs_server.cpp
index cd7adb4be82..570365bb749 100644
--- a/src/server/scripts/Commands/cs_server.cpp
+++ b/src/server/scripts/Commands/cs_server.cpp
@@ -31,6 +31,7 @@ EndScriptData */
#include "GitRevision.h"
#include "Language.h"
#include "Log.h"
+#include "MySQLThreading.h"
#include "ObjectAccessor.h"
#include "Player.h"
#include "RBAC.h"
@@ -44,7 +45,6 @@ EndScriptData */
#include <numeric>
#include <boost/filesystem/operations.hpp>
-#include <mysql_version.h>
#include <openssl/crypto.h>
#include <openssl/opensslv.h>
@@ -137,7 +137,7 @@ public:
handler->PSendSysMessage("%s", GitRevision::GetFullVersion());
handler->PSendSysMessage("Using SSL version: %s (library: %s)", OPENSSL_VERSION_TEXT, SSLeay_version(SSLEAY_VERSION));
handler->PSendSysMessage("Using Boost version: %i.%i.%i", BOOST_VERSION / 100000, BOOST_VERSION / 100 % 1000, BOOST_VERSION % 100);
- handler->PSendSysMessage("Using MySQL version: %s", MYSQL_SERVER_VERSION);
+ handler->PSendSysMessage("Using MySQL version: %s", MySQL::GetLibraryVersion());
handler->PSendSysMessage("Using CMake version: %s", GitRevision::GetCMakeVersion());
handler->PSendSysMessage("Compiled on: %s", GitRevision::GetHostOSVersion());