From d0eae390b61377c569af4bcf2ac647a23a21800b Mon Sep 17 00:00:00 2001 From: Mike Delago <32778141+michaeldelago@users.noreply.github.com> Date: Sun, 21 Jan 2024 08:48:57 -0500 Subject: [PATCH] fix(Core/DatabseWorkerPool): implement DatabaseIncompatibleVersion to better support MariaDB (#18201) * fix(Core): Rework Database Version Check for MariaDB support * incorporate "smarter" version comparison * rename function to be more accurate * Factor magic numbers into defines. Revise comments * clean up triple newline * Doxygenify the docs * remove blankspace --------- Co-authored-by: Kitzunu <24550914+Kitzunu@users.noreply.github.com> --- .../database/Database/DatabaseWorkerPool.cpp | 71 ++++++++++++++++--- .../database/Database/DatabaseWorkerPool.h | 28 ++++++++ .../database/Database/MySQLConnection.cpp | 7 +- .../database/Database/MySQLConnection.h | 1 + 4 files changed, 96 insertions(+), 11 deletions(-) diff --git a/src/server/database/Database/DatabaseWorkerPool.cpp b/src/server/database/Database/DatabaseWorkerPool.cpp index 0273846e1e7f73..94bc7d22d231a4 100644 --- a/src/server/database/Database/DatabaseWorkerPool.cpp +++ b/src/server/database/Database/DatabaseWorkerPool.cpp @@ -33,20 +33,14 @@ #include "WorldDatabase.h" #include #include +#include +#include #ifdef ACORE_DEBUG #include #include #endif -#if MARIADB_VERSION_ID >= 100600 -#define MIN_MYSQL_SERVER_VERSION 100500u -#define MIN_MYSQL_CLIENT_VERSION 30203u -#else -#define MIN_MYSQL_SERVER_VERSION 50700u -#define MIN_MYSQL_CLIENT_VERSION 50700u -#endif - class PingOperation : public SQLOperation { //! Operation for idle delaythreads @@ -377,6 +371,63 @@ void DatabaseWorkerPool::KeepAlive() Enqueue(new PingOperation); } +/** +* @brief Returns true if the version string given is incompatible +* +* Intended to be used with mysql_get_server_info()'s output as the source +* +* DatabaseIncompatibleVersion("8.0.35") => false +* DatabaseIncompatibleVersion("5.6.6") => true +* DatabaseIncompatibleVersion("5.5.5-10.5.5-MariaDB") => false +* DatabaseIncompatibleVersion("5.5.5-10.4.0-MariaDB") => true +* +* Adapted from stackoverflow response +* https://stackoverflow.com/a/2941508 +* +* @param mysqlVersion The output from GetServerInfo()/mysql_get_server_info() +* @return Returns true if the Server version is incompatible +*/ +bool DatabaseIncompatibleVersion(std::string const mysqlVersion) +{ + // anon func to turn a version string into an array of uint8 + // "1.2.3" => [1, 2, 3] + auto parse = [](std::string const& input) + { + std::vector result; + std::istringstream parser(input); + result.push_back(parser.get()); + for (int i = 1; i < 3; i++) + { + // Skip period + parser.get(); + // Append int from parser to output + result.push_back(parser.get()); + } + return result; + }; + + // default to values for MySQL + uint8 offset = 0; + std::string minVersion = MIN_MYSQL_SERVER_VERSION; + + // If the version string contains "MariaDB", use that + if (mysqlVersion.find("MariaDB") != std::string::npos) + { + // All MariaDB 10.X versions have a prefix of 5.5.5 from the + // mysql_get_server_info() function. To make matters more + // annoying, this is removed in MariaDB 11.X + if (mysqlVersion.rfind("5.5.5-", 0) == 0) + offset = 6; + minVersion = MIN_MARIADB_SERVER_VERSION; + } + + auto parsedMySQLVersion = parse(mysqlVersion.substr(offset)); + auto parsedMinVersion = parse(minVersion); + + return std::lexicographical_compare(parsedMySQLVersion.begin(), parsedMySQLVersion.end(), + parsedMinVersion.begin(), parsedMinVersion.end()); +} + template uint32 DatabaseWorkerPool::OpenConnections(InternalIndex type, uint8 numConnections) { @@ -402,10 +453,10 @@ uint32 DatabaseWorkerPool::OpenConnections(InternalIndex type, uint8 numConne _connections[type].clear(); return error; } - else if (connection->GetServerVersion() < MIN_MYSQL_SERVER_VERSION) + else if (DatabaseIncompatibleVersion(connection->GetServerInfo())) { LOG_ERROR("sql.driver", "AzerothCore does not support MySQL versions below 5.7 or MariaDB versions below 10.5.\n\nFound server version: {}. Server compiled with: {}.", - connection->GetServerVersion(), MYSQL_VERSION_ID); + connection->GetServerInfo(), MYSQL_VERSION_ID); return 1; } else diff --git a/src/server/database/Database/DatabaseWorkerPool.h b/src/server/database/Database/DatabaseWorkerPool.h index c7bc7798a45d82..4cf6a2e9237dad 100644 --- a/src/server/database/Database/DatabaseWorkerPool.h +++ b/src/server/database/Database/DatabaseWorkerPool.h @@ -24,6 +24,34 @@ #include #include +/** @file DatabaseWorkerPool.h */ + +/** +* @def MIN_MYSQL_CLIENT_VERSION +* The minimum MariaDB Client Version +* MARIADB_VERSION_ID is defined if using libmariadbclient instead of libmysqlclient +*/ +#if MARIADB_VERSION_ID >= 100600 +#define MIN_MYSQL_CLIENT_VERSION 30203u +#else +/** +* @def MIN_MYSQL_CLIENT_VERSION +* The minimum MySQL Client Version +*/ +#define MIN_MYSQL_CLIENT_VERSION 50700u +#endif + +/** +* @def MIN_MYSQL_SERVER_VERSION +* The minimum MySQL Server Version +*/ +#define MIN_MYSQL_SERVER_VERSION "5.7.0" +/** +* @def MIN_MARIADB_SERVER_VERSION +* The minimum MariaDB Server Version +*/ +#define MIN_MARIADB_SERVER_VERSION "10.5.0" + template class ProducerConsumerQueue; diff --git a/src/server/database/Database/MySQLConnection.cpp b/src/server/database/Database/MySQLConnection.cpp index 73c3653cb84986..3e776059a19c55 100644 --- a/src/server/database/Database/MySQLConnection.cpp +++ b/src/server/database/Database/MySQLConnection.cpp @@ -27,8 +27,8 @@ #include "Timer.h" #include "Tokenize.h" #include "Transaction.h" -#include "Util.h" #include +#include #include MySQLConnectionInfo::MySQLConnectionInfo(std::string_view infoString) @@ -486,6 +486,11 @@ uint32 MySQLConnection::GetServerVersion() const return mysql_get_server_version(m_Mysql); } +std::string MySQLConnection::GetServerInfo() const +{ + return mysql_get_server_info(m_Mysql); +} + MySQLPreparedStatement* MySQLConnection::GetPreparedStatement(uint32 index) { ASSERT(index < m_stmts.size(), "Tried to access invalid prepared statement index {} (max index {}) on database `{}`, connection type: {}", diff --git a/src/server/database/Database/MySQLConnection.h b/src/server/database/Database/MySQLConnection.h index 6e437e2e89f763..08e4f07ac4880a 100644 --- a/src/server/database/Database/MySQLConnection.h +++ b/src/server/database/Database/MySQLConnection.h @@ -94,6 +94,7 @@ friend class PingOperation; void Unlock(); [[nodiscard]] uint32 GetServerVersion() const; + [[nodiscard]] std::string GetServerInfo() const; MySQLPreparedStatement* GetPreparedStatement(uint32 index); void PrepareStatement(uint32 index, std::string_view sql, ConnectionFlags flags);