Core/DBLayer: Support using mysql 8

This commit is contained in:
Shauren
2019-11-01 16:21:14 +01:00
parent 2072258ef4
commit c3a9d56b56
23 changed files with 509 additions and 375 deletions

View File

@@ -86,19 +86,25 @@ find_path(MYSQL_INCLUDE_DIR
/usr/local/include
/usr/local/include/mysql
/usr/local/mysql/include
"${PROGRAM_FILES_64}/MySQL/MySQL Server 8.0/include"
"${PROGRAM_FILES_64}/MySQL/MySQL Server 5.7/include"
"${PROGRAM_FILES_64}/MySQL/MySQL Server 5.6/include"
"${PROGRAM_FILES_64}/MySQL/include"
"${PROGRAM_FILES_32}/MySQL/MySQL Server 8.0/include"
"${PROGRAM_FILES_32}/MySQL/MySQL Server 5.7/include"
"${PROGRAM_FILES_32}/MySQL/MySQL Server 5.6/include"
"${PROGRAM_FILES_32}/MySQL/include"
"C:/MySQL/include"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 8.0;Location]/include"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.7;Location]/include"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.6;Location]/include"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 8.0;Location]/include"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 5.7;Location]/include"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 5.6;Location]/include"
"$ENV{ProgramFiles}/MySQL/MySQL Server 8.0/include"
"$ENV{ProgramFiles}/MySQL/MySQL Server 5.7/include"
"$ENV{ProgramFiles}/MySQL/MySQL Server 5.6/include"
"$ENV{SystemDrive}/MySQL/MySQL Server 8.0/include"
"$ENV{SystemDrive}/MySQL/MySQL Server 5.7/include"
"$ENV{SystemDrive}/MySQL/MySQL Server 5.6/include"
"c:/msys/local/include"
@@ -130,27 +136,37 @@ if( WIN32 )
libmysql
PATHS
${MYSQL_ADD_LIBRARIES_PATH}
"${PROGRAM_FILES_64}/MySQL/MySQL Server 8.0/lib"
"${PROGRAM_FILES_64}/MySQL/MySQL Server 5.7/lib"
"${PROGRAM_FILES_64}/MySQL/MySQL Server 5.6/lib"
"${PROGRAM_FILES_64}/MySQL/MySQL Server 8.0/lib/opt"
"${PROGRAM_FILES_64}/MySQL/MySQL Server 5.7/lib/opt"
"${PROGRAM_FILES_64}/MySQL/MySQL Server 5.6/lib/opt"
"${PROGRAM_FILES_64}/MySQL/lib"
"${PROGRAM_FILES_32}/MySQL/MySQL Server 8.0/lib"
"${PROGRAM_FILES_32}/MySQL/MySQL Server 5.7/lib"
"${PROGRAM_FILES_32}/MySQL/MySQL Server 5.6/lib"
"${PROGRAM_FILES_32}/MySQL/MySQL Server 8.0/lib/opt"
"${PROGRAM_FILES_32}/MySQL/MySQL Server 5.7/lib/opt"
"${PROGRAM_FILES_32}/MySQL/MySQL Server 5.6/lib/opt"
"${PROGRAM_FILES_32}/MySQL/lib"
"C:/MySQL/lib/debug"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 8.0;Location]/lib"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.7;Location]/lib"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.6;Location]/lib"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 8.0;Location]/lib/opt"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.7;Location]/lib/opt"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.6;Location]/lib/opt"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 8.0;Location]/lib"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 5.7;Location]/lib"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 5.6;Location]/lib"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 8.0;Location]/lib/opt"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 5.7;Location]/lib/opt"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 5.6;Location]/lib/opt"
"$ENV{ProgramFiles}/MySQL/MySQL Server 8.0/lib/opt"
"$ENV{ProgramFiles}/MySQL/MySQL Server 5.7/lib/opt"
"$ENV{ProgramFiles}/MySQL/MySQL Server 5.6/lib/opt"
"$ENV{SystemDrive}/MySQL/MySQL Server 8.0/lib/opt"
"$ENV{SystemDrive}/MySQL/MySQL Server 5.7/lib/opt"
"$ENV{SystemDrive}/MySQL/MySQL Server 5.6/lib/opt"
"c:/msys/local/include"
@@ -191,27 +207,37 @@ endif( UNIX )
if( WIN32 )
find_program(MYSQL_EXECUTABLE mysql
PATHS
"${PROGRAM_FILES_64}/MySQL/MySQL Server 8.0/bin"
"${PROGRAM_FILES_64}/MySQL/MySQL Server 5.7/bin"
"${PROGRAM_FILES_64}/MySQL/MySQL Server 5.6/bin"
"${PROGRAM_FILES_64}/MySQL/MySQL Server 8.0/bin/opt"
"${PROGRAM_FILES_64}/MySQL/MySQL Server 5.7/bin/opt"
"${PROGRAM_FILES_64}/MySQL/MySQL Server 5.6/bin/opt"
"${PROGRAM_FILES_64}/MySQL/bin"
"${PROGRAM_FILES_32}/MySQL/MySQL Server 8.0/bin"
"${PROGRAM_FILES_32}/MySQL/MySQL Server 5.7/bin"
"${PROGRAM_FILES_32}/MySQL/MySQL Server 5.6/bin"
"${PROGRAM_FILES_32}/MySQL/MySQL Server 8.0/bin/opt"
"${PROGRAM_FILES_32}/MySQL/MySQL Server 5.7/bin/opt"
"${PROGRAM_FILES_32}/MySQL/MySQL Server 5.6/bin/opt"
"${PROGRAM_FILES_32}/MySQL/bin"
"C:/MySQL/bin/debug"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 8.0;Location]/bin"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.7;Location]/bin"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.6;Location]/bin"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 8.0;Location]/bin/opt"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.7;Location]/bin/opt"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\MySQL AB\\MySQL Server 5.6;Location]/bin/opt"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 8.0;Location]/bin"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 5.7;Location]/bin"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 5.6;Location]/bin"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 8.0;Location]/bin/opt"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 5.7;Location]/bin/opt"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\MySQL AB\\MySQL Server 5.6;Location]/bin/opt"
"$ENV{ProgramFiles}/MySQL/MySQL Server 8.0/bin/opt"
"$ENV{ProgramFiles}/MySQL/MySQL Server 5.7/bin/opt"
"$ENV{ProgramFiles}/MySQL/MySQL Server 5.6/bin/opt"
"$ENV{SystemDrive}/MySQL/MySQL Server 8.0/bin/opt"
"$ENV{SystemDrive}/MySQL/MySQL Server 5.7/bin/opt"
"$ENV{SystemDrive}/MySQL/MySQL Server 5.6/bin/opt"
"c:/msys/local/include"

View File

@@ -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

View File

@@ -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__

View File

@@ -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>

View File

@@ -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;

View File

@@ -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
};

View File

@@ -16,7 +16,7 @@
*/
#include "CharacterDatabase.h"
#include "PreparedStatement.h"
#include "MySQLPreparedStatement.h"
void CharacterDatabaseConnection::DoPrepareStatements()
{

View File

@@ -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) \

View File

@@ -16,7 +16,7 @@
*/
#include "LoginDatabase.h"
#include "PreparedStatement.h"
#include "MySQLPreparedStatement.h"
void LoginDatabaseConnection::DoPrepareStatements()
{

View File

@@ -16,7 +16,7 @@
*/
#include "WorldDatabase.h"
#include "PreparedStatement.h"
#include "MySQLPreparedStatement.h"
void WorldDatabaseConnection::DoPrepareStatements()
{

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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__

View File

@@ -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;
}

View File

@@ -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__

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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>

View File

@@ -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)

View File

@@ -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
{

View File

@@ -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)
{

View File

@@ -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();

View File

@@ -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());