diff options
author | Shauren <shauren.trinity@gmail.com> | 2019-11-01 16:21:14 +0100 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2019-11-01 16:21:14 +0100 |
commit | c3a9d56b56b665133707f587ecb1bd1c272f6911 (patch) | |
tree | 02dfce1fa605569e3212fbe8804125d55957d7bf /src/server/database/Database | |
parent | 2072258ef44e89e30256d529686ae2b8dc2b5f0d (diff) |
Core/DBLayer: Support using mysql 8
Diffstat (limited to 'src/server/database/Database')
20 files changed, 479 insertions, 371 deletions
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(); |