From cecb36bd68d30408a0741b161318aadc70a81e20 Mon Sep 17 00:00:00 2001 From: Shauren Date: Mon, 2 Mar 2020 22:50:56 +0100 Subject: Core/DBLayer: Use std::variant's stored type instead of relying on our own separate enum for prepared statement parameters (cherry picked from commit 30482038559d65648d9bcfa29cd426a6f266eeba) --- .../database/Database/MySQLPreparedStatement.cpp | 218 ++++----------------- 1 file changed, 36 insertions(+), 182 deletions(-) (limited to 'src/server/database/Database/MySQLPreparedStatement.cpp') diff --git a/src/server/database/Database/MySQLPreparedStatement.cpp b/src/server/database/Database/MySQLPreparedStatement.cpp index f7d72dfad98..30205d68fa2 100644 --- a/src/server/database/Database/MySQLPreparedStatement.cpp +++ b/src/server/database/Database/MySQLPreparedStatement.cpp @@ -20,7 +20,20 @@ #include "Log.h" #include "MySQLHacks.h" #include "PreparedStatement.h" -#include + +template +struct MySQLType { }; + +template<> struct MySQLType : std::integral_constant { }; +template<> struct MySQLType : std::integral_constant { }; +template<> struct MySQLType : std::integral_constant { }; +template<> struct MySQLType : std::integral_constant { }; +template<> struct MySQLType : std::integral_constant { }; +template<> struct MySQLType : std::integral_constant { }; +template<> struct MySQLType : std::integral_constant { }; +template<> struct MySQLType : std::integral_constant { }; +template<> struct MySQLType : std::integral_constant { }; +template<> struct MySQLType : std::integral_constant { }; MySQLPreparedStatement::MySQLPreparedStatement(MySQLStmt* stmt, std::string queryString) : m_stmt(nullptr), m_Mstmt(stmt), m_bind(nullptr), m_queryString(std::move(queryString)) @@ -55,51 +68,10 @@ void MySQLPreparedStatement::BindParameters(PreparedStatementBase* stmt) uint8 pos = 0; for (PreparedStatementData const& data : stmt->GetParameters()) { - switch (data.type) + std::visit([&](auto&& param) { - case TYPE_BOOL: - setBool(pos, std::get(data.data)); - break; - case TYPE_UI8: - setUInt8(pos, std::get(data.data)); - break; - case TYPE_UI16: - setUInt16(pos, std::get(data.data)); - break; - case TYPE_UI32: - setUInt32(pos, std::get(data.data)); - break; - case TYPE_I8: - setInt8(pos, std::get(data.data)); - break; - case TYPE_I16: - setInt16(pos, std::get(data.data)); - break; - case TYPE_I32: - setInt32(pos, std::get(data.data)); - break; - case TYPE_UI64: - setUInt64(pos, std::get(data.data)); - break; - case TYPE_I64: - setInt64(pos, std::get(data.data)); - break; - case TYPE_FLOAT: - setFloat(pos, std::get(data.data)); - break; - case TYPE_DOUBLE: - setDouble(pos, std::get(data.data)); - break; - case TYPE_STRING: - setString(pos, std::get(data.data)); - break; - case TYPE_BINARY: - setBinary(pos, std::get>(data.data)); - break; - case TYPE_NULL: - setNull(pos); - break; - } + SetParameter(pos, param); + }, data.data); ++pos; } #ifdef _DEBUG @@ -126,19 +98,6 @@ static bool ParamenterIndexAssertFail(uint32 stmtIndex, uint8 index, uint32 para return false; } -static void SetParameterValue(MYSQL_BIND* param, enum_field_types type, const void* value, uint32 len, bool isUnsigned) -{ - param->buffer_type = type; - delete[] static_cast(param->buffer); - param->buffer = new char[len]; - param->buffer_length = 0; - param->is_null_value = 0; - param->length = nullptr; // Only != NULL for strings - param->is_unsigned = isUnsigned; - - memcpy(param->buffer, value, len); -} - //- Bind on mysql level void MySQLPreparedStatement::AssertValidIndex(uint8 index) { @@ -148,7 +107,7 @@ void MySQLPreparedStatement::AssertValidIndex(uint8 index) TC_LOG_ERROR("sql.sql", "[ERROR] Prepared Statement (id: %u) trying to bind value on already bound index (%u).", m_stmt->GetIndex(), index); } -void MySQLPreparedStatement::setNull(const uint8 index) +void MySQLPreparedStatement::SetParameter(uint8 index, std::nullptr_t) { AssertValidIndex(index); m_paramsSet[index] = true; @@ -162,92 +121,30 @@ void MySQLPreparedStatement::setNull(const uint8 index) param->length = nullptr; } -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) +void MySQLPreparedStatement::SetParameter(uint8 index, bool value) { - AssertValidIndex(index); - m_paramsSet[index] = true; - MYSQL_BIND* param = &m_bind[index]; - SetParameterValue(param, MYSQL_TYPE_LONGLONG, &value, sizeof(int64), false); + SetParameter(index, uint8(value ? 1 : 0)); } -void MySQLPreparedStatement::setFloat(const uint8 index, const float value) +template +void MySQLPreparedStatement::SetParameter(uint8 index, T value) { AssertValidIndex(index); m_paramsSet[index] = true; MYSQL_BIND* param = &m_bind[index]; - SetParameterValue(param, MYSQL_TYPE_FLOAT, &value, sizeof(float), (value > 0.0f)); -} + uint32 len = uint32(sizeof(T)); + param->buffer_type = MySQLType::value; + delete[] static_cast(param->buffer); + param->buffer = new char[len]; + param->buffer_length = 0; + param->is_null_value = 0; + param->length = nullptr; // Only != NULL for strings + param->is_unsigned = std::is_unsigned_v; -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)); + memcpy(param->buffer, &value, len); } -void MySQLPreparedStatement::setString(const uint8 index, const std::string& value) +void MySQLPreparedStatement::SetParameter(uint8 index, std::string const& value) { AssertValidIndex(index); m_paramsSet[index] = true; @@ -264,7 +161,7 @@ void MySQLPreparedStatement::setString(const uint8 index, const std::string& val memcpy(param->buffer, value.c_str(), len); } -void MySQLPreparedStatement::setBinary(const uint8 index, const std::vector& value) +void MySQLPreparedStatement::SetParameter(uint8 index, std::vector const& value) { AssertValidIndex(index); m_paramsSet[index] = true; @@ -289,55 +186,12 @@ std::string MySQLPreparedStatement::getQueryString() const for (PreparedStatementData const& data : m_stmt->GetParameters()) { pos = queryString.find('?', pos); - std::stringstream ss; - switch (data.type) + std::string replaceStr = std::visit([&](auto&& data) { - case TYPE_BOOL: - ss << uint16(std::get(data.data)); // stringstream will append a character with that code instead of numeric representation - break; - case TYPE_UI8: - ss << uint16(std::get(data.data)); // stringstream will append a character with that code instead of numeric representation - break; - case TYPE_UI16: - ss << std::get(data.data); - break; - case TYPE_UI32: - ss << std::get(data.data); - break; - case TYPE_I8: - ss << int16(std::get(data.data)); // stringstream will append a character with that code instead of numeric representation - break; - case TYPE_I16: - ss << std::get(data.data); - break; - case TYPE_I32: - ss << std::get(data.data); - break; - case TYPE_UI64: - ss << std::get(data.data); - break; - case TYPE_I64: - ss << std::get(data.data); - break; - case TYPE_FLOAT: - ss << std::get(data.data); - break; - case TYPE_DOUBLE: - ss << std::get(data.data); - break; - case TYPE_STRING: - ss << '\'' << std::get(data.data) << '\''; - break; - case TYPE_BINARY: - ss << "BINARY"; - break; - case TYPE_NULL: - ss << "NULL"; - break; - } + return PreparedStatementData::ToString(data); + }, data.data); - std::string replaceStr = ss.str(); queryString.replace(pos, 1, replaceStr); pos += replaceStr.length(); } -- cgit v1.2.3