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:
@@ -23,6 +23,7 @@
|
||||
/data/sql/custom/*
|
||||
/src/server/scripts/Custom/*
|
||||
!/src/server/scripts/Custom/README.md
|
||||
!/src/server/scripts/Custom/custom_script_loader.cpp
|
||||
|
||||
/*.override.yml
|
||||
/*.override.yaml
|
||||
|
||||
+1
-1
@@ -106,7 +106,7 @@ include(ConfigInstall)
|
||||
CU_RUN_HOOK("AFTER_LOAD_CMAKE_MODULES")
|
||||
|
||||
find_package(PCHSupport)
|
||||
find_package(MySQL REQUIRED)
|
||||
find_package(MySQL REQUIRED COMPONENTS lib)
|
||||
|
||||
if(UNIX AND WITH_PERFTOOLS)
|
||||
find_package(Gperftools)
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -32,12 +32,24 @@
|
||||
*/
|
||||
#define MIN_MYSQL_CLIENT_VERSION 80000u
|
||||
|
||||
/**
|
||||
* @def MIN_MARIADB_CLIENT_VERSION_ID
|
||||
* Minimum MariaDB connector MARIADB_VERSION_ID (10.4.0 => 100400)
|
||||
*/
|
||||
#define MIN_MARIADB_CLIENT_VERSION_ID 100400u
|
||||
|
||||
/**
|
||||
* @def MIN_MYSQL_SERVER_VERSION
|
||||
* The minimum MySQL Server Version
|
||||
*/
|
||||
#define MIN_MYSQL_SERVER_VERSION "8.0.0"
|
||||
|
||||
/**
|
||||
* @def MIN_MARIADB_SERVER_VERSION
|
||||
* Minimum MariaDB server (version triplet after the 5.5.5- compatibility prefix)
|
||||
*/
|
||||
#define MIN_MARIADB_SERVER_VERSION "10.4.0"
|
||||
|
||||
template <typename T>
|
||||
class ProducerConsumerQueue;
|
||||
|
||||
|
||||
@@ -129,13 +129,17 @@ uint32 MySQLConnection::Open()
|
||||
|
||||
if (m_connectionInfo.ssl != "")
|
||||
{
|
||||
#ifdef MARIADB_VERSION_ID
|
||||
my_bool const ssl_enforce = (m_connectionInfo.ssl == "ssl") ? 1 : 0;
|
||||
if (ssl_enforce)
|
||||
mysql_options(mysqlInit, MYSQL_OPT_SSL_ENFORCE, &ssl_enforce);
|
||||
#else
|
||||
mysql_ssl_mode opt_use_ssl = SSL_MODE_DISABLED;
|
||||
if (m_connectionInfo.ssl == "ssl")
|
||||
{
|
||||
opt_use_ssl = SSL_MODE_REQUIRED;
|
||||
}
|
||||
|
||||
mysql_options(mysqlInit, MYSQL_OPT_SSL_MODE, (char const*)&opt_use_ssl);
|
||||
#endif
|
||||
}
|
||||
|
||||
m_Mysql = reinterpret_cast<MySQLHandle*>(mysql_real_connect(mysqlInit, m_connectionInfo.host.c_str(), m_connectionInfo.user.c_str(),
|
||||
@@ -216,7 +220,7 @@ bool MySQLConnection::Execute(PreparedStatementBase* stmt)
|
||||
|
||||
uint32 _s = getMSTime();
|
||||
|
||||
#if MYSQL_VERSION_ID >= 80300
|
||||
#if MYSQL_VERSION_ID >= 80300 && !defined(MARIADB_VERSION_ID)
|
||||
if (mysql_stmt_bind_named_param(msql_STMT, msql_BIND, m_mStmt->GetParameterCount(), nullptr))
|
||||
#else
|
||||
if (mysql_stmt_bind_param(msql_STMT, msql_BIND))
|
||||
@@ -268,7 +272,7 @@ bool MySQLConnection::_Query(PreparedStatementBase* stmt, MySQLPreparedStatement
|
||||
|
||||
uint32 _s = getMSTime();
|
||||
|
||||
#if MYSQL_VERSION_ID >= 80300
|
||||
#if MYSQL_VERSION_ID >= 80300 && !defined(MARIADB_VERSION_ID)
|
||||
if (mysql_stmt_bind_named_param(msql_STMT, msql_BIND, m_mStmt->GetParameterCount(), nullptr))
|
||||
#else
|
||||
if (mysql_stmt_bind_param(msql_STMT, msql_BIND))
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
// This is where scripts' loading functions should be declared:
|
||||
// void MyExampleScript()
|
||||
|
||||
// The name of this function should match:
|
||||
// void Add${NameOfDirectory}Scripts()
|
||||
void AddCustomScripts()
|
||||
{
|
||||
// MyExampleScript()
|
||||
}
|
||||
Reference in New Issue
Block a user