fix(db): MariaDB 10.6+ server and connector compatibility

- Parse real MariaDB version after MySQL 5.5.5 compatibility prefix for
  DatabaseIncompatibleVersion checks.
- Relax client checks when building against MariaDB C connector
  (MARIADB_VERSION_ID); keep Oracle MySQL 8.0+ rules otherwise.
- Use mysql_stmt_bind_param on MariaDB; mysql_stmt_bind_named_param only for
  MySQL 8.3+ without MariaDB headers.
- SSL: MYSQL_OPT_SSL_ENFORCE on MariaDB connector, MYSQL_OPT_SSL_MODE elsewhere.
- Track custom_script_loader.cpp so static script link succeeds; CMake
  find_package(MySQL) requires COMPONENTS lib on CMake 3.16.
This commit is contained in:
Dawnforger
2026-05-08 20:11:43 -05:00
parent 22e79a4f32
commit 2f8c374569
6 changed files with 107 additions and 27 deletions
@@ -31,6 +31,7 @@
#include "SQLOperation.h"
#include "Transaction.h"
#include "WorldDatabase.h"
#include <array>
#include <limits>
#include <mysqld_error.h>
#include <sstream>
@@ -59,10 +60,18 @@ DatabaseWorkerPool<T>::DatabaseWorkerPool() :
{
WPFatal(mysql_thread_safe(), "Used MySQL library isn't thread-safe.");
bool isSupportClientDB = mysql_get_client_version() >= MIN_MYSQL_CLIENT_VERSION;
bool isSameClientDB = mysql_get_client_version() == MYSQL_VERSION_ID;
bool isSupportClientDB;
bool isSameClientDB;
#ifdef MARIADB_VERSION_ID
isSupportClientDB = (MARIADB_VERSION_ID >= MIN_MARIADB_CLIENT_VERSION_ID);
// MariaDB packages often differ between build host and runtime; strict id match is too brittle.
isSameClientDB = true;
#else
isSupportClientDB = mysql_get_client_version() >= MIN_MYSQL_CLIENT_VERSION;
isSameClientDB = mysql_get_client_version() == MYSQL_VERSION_ID;
#endif
WPFatal(isSupportClientDB, "AzerothCore does not support MySQL versions below 8.0\n\nFound version: {} / {}. Server compiled with: {}.\nSearch the wiki for ACE00043 in Common Errors (https://www.azerothcore.org/wiki/common-errors#ace00043).",
WPFatal(isSupportClientDB, "AzerothCore does not support this database client library.\n\nFound version: {} / {}. Server compiled with: {}.\nSearch the wiki for ACE00043 in Common Errors (https://www.azerothcore.org/wiki/common-errors#ace00043).",
mysql_get_client_info(), mysql_get_client_version(), MYSQL_VERSION_ID);
WPFatal(isSameClientDB, "Used MySQL library version ({} id {}) does not match the version id used to compile AzerothCore (id {}).\nSearch the wiki for ACE00046 in Common Errors (https://www.azerothcore.org/wiki/common-errors#ace00046).",
mysql_get_client_info(), mysql_get_client_version(), MYSQL_VERSION_ID);
@@ -386,32 +395,60 @@ void DatabaseWorkerPool<T>::KeepAlive()
*/
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)
auto parseTriplet = [](std::string const& input) -> std::array<unsigned, 3>
{
std::vector<uint8> result;
std::istringstream parser(input);
result.push_back(parser.get());
for (int i = 1; i < 3; i++)
std::array<unsigned, 3> v = { 0, 0, 0 };
size_t idx = 0;
std::string num;
for (char ch : input)
{
// Skip period
parser.get();
// Append int from parser to output
result.push_back(parser.get());
if (ch >= '0' && ch <= '9')
num.push_back(ch);
else if (ch == '.')
{
if (!num.empty() && idx < 3)
{
v[idx++] = static_cast<unsigned>(std::stoul(num));
num.clear();
}
}
else
break;
}
return result;
if (!num.empty() && idx < 3)
v[idx] = static_cast<unsigned>(std::stoul(num));
return v;
};
// default to values for MySQL
uint8 offset = 0;
auto compareVersion = [](std::array<unsigned, 3> const& a, std::array<unsigned, 3> const& b) -> int
{
if (a[0] != b[0])
return (a[0] < b[0]) ? -1 : 1;
if (a[1] != b[1])
return (a[1] < b[1]) ? -1 : 1;
if (a[2] != b[2])
return (a[2] < b[2]) ? -1 : 1;
return 0;
};
std::string ver = mysqlVersion;
std::string minVersion = MIN_MYSQL_SERVER_VERSION;
auto parsedMySQLVersion = parse(mysqlVersion.substr(offset));
auto parsedMinVersion = parse(minVersion);
// MariaDB: mysql_get_server_info() often starts with MySQL-compat "5.5.5-" then real version, e.g.
// "5.5.5-10.6.11-MariaDB-1:10.6.11+maria~ubu2004"
if (ver.find("MariaDB") != std::string::npos)
{
size_t const firstDash = ver.find('-');
if (firstDash != std::string::npos)
{
size_t const secondDash = ver.find('-', firstDash + 1);
if (secondDash != std::string::npos)
ver = ver.substr(firstDash + 1, secondDash - firstDash - 1);
}
minVersion = MIN_MARIADB_SERVER_VERSION;
}
return std::lexicographical_compare(parsedMySQLVersion.begin(), parsedMySQLVersion.end(),
parsedMinVersion.begin(), parsedMinVersion.end());
return compareVersion(parseTriplet(ver), parseTriplet(minVersion)) < 0;
}
template <class T>
@@ -442,7 +479,7 @@ uint32 DatabaseWorkerPool<T>::OpenConnections(InternalIndex type, uint8 numConne
}
else if (DatabaseIncompatibleVersion(connection->GetServerInfo()))
{
LOG_ERROR("sql.driver", "AzerothCore does not support MySQL versions below 8.0\n\nFound server version: {}. Server compiled with: {}.",
LOG_ERROR("sql.driver", "Database server version is too old.\n\nFound server version: {}. Client library compile id: {}.",
connection->GetServerInfo(), MYSQL_VERSION_ID);
return 1;
}