mirror of
https://gitcode.com/GitHub_Trending/az/azerothcore-wotlk.git
synced 2026-10-10 07:06:38 +08:00
feat(Core/Database): enable modules to own their database (#27544)
Co-authored-by: UndeadRogue <[email protected]> Co-authored-by: UltraNix <[email protected]> Co-authored-by: 郑佩茹 <[email protected]> Co-authored-by: Yunfan Li <[email protected]> Co-authored-by: kadeshar <[email protected]> Co-authored-by: sudlud <[email protected]> Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
This commit is contained in:
co-authored by
UndeadRogue
UltraNix
郑佩茹
Yunfan Li
kadeshar
sudlud
Claude Opus 5
parent
e962278b9b
commit
e1823bb2db
@@ -446,6 +446,9 @@ bool StartDB()
|
||||
if (!loader.Load())
|
||||
return false;
|
||||
|
||||
if (!sScriptMgr->OnModuleDatabasesLoading())
|
||||
return false;
|
||||
|
||||
///- Get the realm Id from the configuration file
|
||||
realm.Id.Realm = sConfigMgr->GetOption<uint32>("RealmID", 1);
|
||||
if (!realm.Id.Realm)
|
||||
@@ -494,6 +497,8 @@ void StopDB()
|
||||
WorldDatabase.Close();
|
||||
LoginDatabase.Close();
|
||||
|
||||
sScriptMgr->OnModuleDatabasesClosing();
|
||||
|
||||
MySQL::Library_End();
|
||||
}
|
||||
|
||||
@@ -584,6 +589,8 @@ void WorldUpdateLoop()
|
||||
CharacterDatabase.WarnAboutSyncQueries(true);
|
||||
WorldDatabase.WarnAboutSyncQueries(true);
|
||||
|
||||
sScriptMgr->OnDatabaseWarnAboutSyncQueries(true);
|
||||
|
||||
///- While we have not World::m_stopEvent, update the world
|
||||
while (!World::IsStopped())
|
||||
{
|
||||
@@ -613,6 +620,8 @@ void WorldUpdateLoop()
|
||||
#endif
|
||||
}
|
||||
|
||||
sScriptMgr->OnDatabaseWarnAboutSyncQueries(false);
|
||||
|
||||
LoginDatabase.WarnAboutSyncQueries(false);
|
||||
CharacterDatabase.WarnAboutSyncQueries(false);
|
||||
WorldDatabase.WarnAboutSyncQueries(false);
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef DATABASE_UPDATE_POOL_H
|
||||
#define DATABASE_UPDATE_POOL_H
|
||||
|
||||
#include "Define.h"
|
||||
#include "MySQLConnection.h"
|
||||
#include "QueryResult.h"
|
||||
#include <string_view>
|
||||
|
||||
// Minimal pool interface the DB updater operates on. Core pools reach it through
|
||||
// DatabaseWorkerPoolAdapter; modules can implement it directly (see ModuleDatabasePool).
|
||||
struct AC_DATABASE_API DatabaseUpdatePool
|
||||
{
|
||||
virtual ~DatabaseUpdatePool() = default;
|
||||
|
||||
virtual void DirectExecute(std::string_view query) = 0;
|
||||
virtual QueryResult Query(std::string_view query) = 0;
|
||||
virtual MySQLConnectionInfo const* GetConnectionInfo() const = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef DATABASE_WORKER_POOL_ADAPTER_H
|
||||
#define DATABASE_WORKER_POOL_ADAPTER_H
|
||||
|
||||
#include "DatabaseUpdatePool.h"
|
||||
#include "DatabaseWorkerPool.h"
|
||||
|
||||
template <class T>
|
||||
class DatabaseWorkerPoolAdapter : public DatabaseUpdatePool
|
||||
{
|
||||
public:
|
||||
DatabaseWorkerPoolAdapter(DatabaseWorkerPool<T>& pool) : _pool(pool) {}
|
||||
|
||||
void DirectExecute(std::string_view query) override
|
||||
{
|
||||
_pool.DirectExecute(query);
|
||||
}
|
||||
|
||||
QueryResult Query(std::string_view query) override
|
||||
{
|
||||
return _pool.Query(query);
|
||||
}
|
||||
|
||||
MySQLConnectionInfo const* GetConnectionInfo() const override
|
||||
{
|
||||
return _pool.GetConnectionInfo();
|
||||
}
|
||||
|
||||
private:
|
||||
DatabaseWorkerPool<T>& _pool;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,264 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#include "ModuleDatabasePool.h"
|
||||
#include "Errors.h"
|
||||
#include "Log.h"
|
||||
#include "MySQLConnection.h"
|
||||
#include "MySQLPreparedStatement.h"
|
||||
#include "QueryResult.h"
|
||||
#include "Transaction.h"
|
||||
#include <errmsg.h>
|
||||
#include <limits>
|
||||
#include <mysqld_error.h>
|
||||
#include <thread>
|
||||
|
||||
ModuleDatabasePool::ModuleDatabasePool()
|
||||
: _connectionInfo(""), _synchThreads(0)
|
||||
{
|
||||
}
|
||||
|
||||
ModuleDatabasePool::~ModuleDatabasePool()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
void ModuleDatabasePool::SetConnectionInfo(std::string_view infoString, uint8 synchThreads)
|
||||
{
|
||||
_connectionInfo = MySQLConnectionInfo(infoString);
|
||||
_synchThreads = synchThreads;
|
||||
}
|
||||
|
||||
uint32 ModuleDatabasePool::Open()
|
||||
{
|
||||
if (!_synchThreads)
|
||||
{
|
||||
LOG_ERROR("sql.driver", "ModuleDatabasePool: database `{}` was configured with 0 synchronous connections, "
|
||||
"at least one is required.", _connectionInfo.database);
|
||||
return CR_UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
Close();
|
||||
|
||||
for (uint8 i = 0; i < _synchThreads; ++i)
|
||||
{
|
||||
auto conn = std::unique_ptr<MySQLConnection>(CreateConnection(_connectionInfo));
|
||||
uint32 result = conn->Open();
|
||||
if (result != 0)
|
||||
{
|
||||
LOG_ERROR("sql.driver", "ModuleDatabasePool: could not open connection {}/{} to database `{}`, error {}",
|
||||
i + 1, _synchThreads, _connectionInfo.database, result);
|
||||
Close();
|
||||
return result;
|
||||
}
|
||||
|
||||
_connections.push_back(std::move(conn));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ModuleDatabasePool::PrepareStatements()
|
||||
{
|
||||
for (auto const& conn : _connections)
|
||||
{
|
||||
conn->LockIfReady();
|
||||
if (!conn->PrepareStatements())
|
||||
{
|
||||
conn->Unlock();
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
|
||||
conn->Unlock();
|
||||
}
|
||||
|
||||
if (!_connections.empty())
|
||||
{
|
||||
MySQLConnection const* conn = _connections.front().get();
|
||||
_preparedStatementSize.assign(conn->m_stmts.size(), 0);
|
||||
for (std::size_t i = 0; i < conn->m_stmts.size(); ++i)
|
||||
{
|
||||
if (MySQLPreparedStatement* stmt = conn->m_stmts[i].get())
|
||||
{
|
||||
uint32 const paramCount = stmt->GetParameterCount();
|
||||
ASSERT(paramCount < std::numeric_limits<uint8>::max());
|
||||
_preparedStatementSize[i] = static_cast<uint8>(paramCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ModuleDatabasePool::Close()
|
||||
{
|
||||
_connections.clear();
|
||||
|
||||
_preparedStatementSize.clear();
|
||||
}
|
||||
|
||||
void ModuleDatabasePool::Execute(std::string_view sql)
|
||||
{
|
||||
// Synchronous for now - kept separate from DirectExecute so async execution
|
||||
// can be added later without touching callers.
|
||||
DirectExecute(sql);
|
||||
}
|
||||
|
||||
void ModuleDatabasePool::DirectExecute(std::string_view sql)
|
||||
{
|
||||
if (sql.empty())
|
||||
return;
|
||||
|
||||
if (_connections.empty())
|
||||
return;
|
||||
|
||||
MySQLConnection* conn = GetFreeConnection();
|
||||
conn->Execute(sql);
|
||||
conn->Unlock();
|
||||
}
|
||||
|
||||
QueryResult ModuleDatabasePool::Query(std::string_view sql)
|
||||
{
|
||||
if (_connections.empty())
|
||||
return QueryResult(nullptr);
|
||||
|
||||
MySQLConnection* conn = GetFreeConnection();
|
||||
ResultSet* result = conn->Query(sql);
|
||||
conn->Unlock();
|
||||
|
||||
// Mirror DatabaseWorkerPool<T>::Query semantics: nullptr for empty results,
|
||||
// and the first row loaded before the result is handed out.
|
||||
if (!result || !result->GetRowCount() || !result->NextRow())
|
||||
{
|
||||
delete result;
|
||||
return QueryResult(nullptr);
|
||||
}
|
||||
|
||||
return QueryResult(result);
|
||||
}
|
||||
|
||||
void ModuleDatabasePool::Execute(PreparedStatementBase* stmt)
|
||||
{
|
||||
if (_connections.empty())
|
||||
{
|
||||
delete stmt;
|
||||
return;
|
||||
}
|
||||
|
||||
MySQLConnection* conn = GetFreeConnection();
|
||||
conn->Execute(stmt);
|
||||
conn->Unlock();
|
||||
|
||||
delete stmt;
|
||||
}
|
||||
|
||||
PreparedQueryResult ModuleDatabasePool::Query(PreparedStatementBase* stmt)
|
||||
{
|
||||
if (_connections.empty())
|
||||
{
|
||||
delete stmt;
|
||||
return PreparedQueryResult(nullptr);
|
||||
}
|
||||
|
||||
MySQLConnection* conn = GetFreeConnection();
|
||||
PreparedResultSet* result = conn->Query(stmt);
|
||||
conn->Unlock();
|
||||
|
||||
//! Delete proxy-class. Not needed anymore
|
||||
delete stmt;
|
||||
|
||||
if (!result || !result->GetRowCount())
|
||||
{
|
||||
delete result;
|
||||
return PreparedQueryResult(nullptr);
|
||||
}
|
||||
|
||||
return PreparedQueryResult(result);
|
||||
}
|
||||
|
||||
uint8 ModuleDatabasePool::GetPreparedStatementParamCount(uint32 index) const
|
||||
{
|
||||
return index < _preparedStatementSize.size() ? _preparedStatementSize[index] : 0;
|
||||
}
|
||||
|
||||
void ModuleDatabasePool::DirectCommitTransaction(std::shared_ptr<TransactionBase> transaction)
|
||||
{
|
||||
if (_connections.empty())
|
||||
return;
|
||||
|
||||
MySQLConnection* conn = GetFreeConnection();
|
||||
int errorCode = conn->ExecuteTransaction(transaction);
|
||||
if (!errorCode)
|
||||
{
|
||||
conn->Unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
//! Handle MySQL Errno 1213 without extending deadlock to the core itself
|
||||
if (errorCode == ER_LOCK_DEADLOCK)
|
||||
{
|
||||
uint8 constexpr loopBreaker = 5;
|
||||
for (uint8 i = 0; i < loopBreaker; ++i)
|
||||
{
|
||||
if (!conn->ExecuteTransaction(transaction))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
transaction->Cleanup();
|
||||
conn->Unlock();
|
||||
}
|
||||
|
||||
void ModuleDatabasePool::KeepAlive()
|
||||
{
|
||||
//! Ping connections that are not busy; a locked connection is in use and alive.
|
||||
for (auto const& conn : _connections)
|
||||
{
|
||||
if (conn->LockIfReady())
|
||||
{
|
||||
conn->Ping();
|
||||
conn->Unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MySQLConnection* ModuleDatabasePool::GetFreeConnection()
|
||||
{
|
||||
uint8 i = 0;
|
||||
auto const num_cons = _connections.size();
|
||||
MySQLConnection* connection = nullptr;
|
||||
|
||||
//! Block forever until a connection is free
|
||||
for (;;)
|
||||
{
|
||||
connection = _connections[++i % num_cons].get();
|
||||
//! Must be matched with connection->Unlock() or you will get deadlocks
|
||||
if (connection->LockIfReady())
|
||||
break;
|
||||
|
||||
if (i % num_cons == 0)
|
||||
std::this_thread::yield();
|
||||
}
|
||||
|
||||
return connection;
|
||||
}
|
||||
|
||||
MySQLConnectionInfo const* ModuleDatabasePool::GetConnectionInfo() const
|
||||
{
|
||||
return &_connectionInfo;
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef MODULE_DATABASE_POOL_H
|
||||
#define MODULE_DATABASE_POOL_H
|
||||
|
||||
#include "DatabaseEnvFwd.h"
|
||||
#include "DatabaseUpdatePool.h"
|
||||
#include "Define.h"
|
||||
#include "MySQLConnection.h"
|
||||
#include "PreparedStatement.h"
|
||||
#include "StringFormat.h"
|
||||
#include <memory>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
class TransactionBase;
|
||||
|
||||
// Base class for module-owned database pools. A module derives from this,
|
||||
// implements CreateConnection with its own MySQLConnection subclass (carrying
|
||||
// the module's prepared statements), and gets open/execute/query plus DBUpdater
|
||||
// compatibility without any core-side registration.
|
||||
//
|
||||
// Connections are synchronous; asynchronous execution can be added in a
|
||||
// follow-up without changing this interface. DoPrepareStatements must mark every
|
||||
// statement CONNECTION_SYNCH: a CONNECTION_ASYNC one is skipped on these
|
||||
// connections and asserts on first use.
|
||||
class AC_DATABASE_API ModuleDatabasePool : public DatabaseUpdatePool
|
||||
{
|
||||
public:
|
||||
ModuleDatabasePool();
|
||||
virtual ~ModuleDatabasePool();
|
||||
|
||||
void SetConnectionInfo(std::string_view infoString, uint8 synchThreads);
|
||||
|
||||
//! Opens the configured number of synchronous connections.
|
||||
//! Returns 0 on success, or the MySQL error code of the first failed connection.
|
||||
uint32 Open();
|
||||
|
||||
//! Prepares the connection statements. Call after the schema exists
|
||||
//! (post create/populate/update), mirroring DatabaseLoader's ordering.
|
||||
bool PrepareStatements();
|
||||
|
||||
void Close();
|
||||
|
||||
void Execute(std::string_view sql);
|
||||
void DirectExecute(std::string_view sql) override;
|
||||
QueryResult Query(std::string_view sql) override;
|
||||
MySQLConnectionInfo const* GetConnectionInfo() const override;
|
||||
|
||||
//! Format variants, mirroring DatabaseWorkerPool.
|
||||
template<typename... Args>
|
||||
void Execute(std::string_view sql, Args&&... args)
|
||||
{
|
||||
if (sql.empty())
|
||||
return;
|
||||
|
||||
Execute(std::string_view(Acore::StringFormat(sql, std::forward<Args>(args)...)));
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void DirectExecute(std::string_view sql, Args&&... args)
|
||||
{
|
||||
if (sql.empty())
|
||||
return;
|
||||
|
||||
DirectExecute(std::string_view(Acore::StringFormat(sql, std::forward<Args>(args)...)));
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
QueryResult Query(std::string_view sql, Args&&... args)
|
||||
{
|
||||
if (sql.empty())
|
||||
return QueryResult(nullptr);
|
||||
|
||||
return Query(std::string_view(Acore::StringFormat(sql, std::forward<Args>(args)...)));
|
||||
}
|
||||
|
||||
//! Prepared statements. The index space is defined by the module's connection
|
||||
//! class (DoPrepareStatements); parameter counts are recorded by PrepareStatements(),
|
||||
//! so building one before that call yields a zero-parameter statement.
|
||||
//! Both calls consume (delete) the statement, mirroring DatabaseWorkerPool.
|
||||
void Execute(PreparedStatementBase* stmt);
|
||||
PreparedQueryResult Query(PreparedStatementBase* stmt);
|
||||
|
||||
//! Parameter count for a prepared statement index, for constructing typed
|
||||
//! PreparedStatement<T> objects module-side.
|
||||
[[nodiscard]] uint8 GetPreparedStatementParamCount(uint32 index) const;
|
||||
|
||||
//! Synchronously commits the transaction on a free connection.
|
||||
void DirectCommitTransaction(std::shared_ptr<TransactionBase> transaction);
|
||||
|
||||
//! Pings every idle connection to keep them alive.
|
||||
void KeepAlive();
|
||||
|
||||
protected:
|
||||
virtual MySQLConnection* CreateConnection(MySQLConnectionInfo& connInfo) = 0;
|
||||
|
||||
private:
|
||||
MySQLConnection* GetFreeConnection();
|
||||
|
||||
MySQLConnectionInfo _connectionInfo;
|
||||
std::vector<std::unique_ptr<MySQLConnection>> _connections;
|
||||
std::vector<uint8> _preparedStatementSize;
|
||||
uint8 _synchThreads;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -56,6 +56,7 @@ class AC_DATABASE_API MySQLConnection
|
||||
template <class T>
|
||||
friend class DatabaseWorkerPool;
|
||||
|
||||
friend class ModuleDatabasePool;
|
||||
friend class PingOperation;
|
||||
|
||||
public:
|
||||
|
||||
@@ -31,6 +31,7 @@ class AC_DATABASE_API TransactionBase
|
||||
{
|
||||
friend class TransactionTask;
|
||||
friend class MySQLConnection;
|
||||
friend class ModuleDatabasePool;
|
||||
|
||||
template <typename T>
|
||||
friend class DatabaseWorkerPool;
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "Config.h"
|
||||
#include "DatabaseEnv.h"
|
||||
#include "DatabaseLoader.h"
|
||||
#include "DatabaseWorkerPoolAdapter.h"
|
||||
#include "Log.h"
|
||||
#include "StartProcess.h"
|
||||
#include "UpdateFetcher.h"
|
||||
@@ -93,10 +94,16 @@ std::string DBUpdater<LoginDatabaseConnection>::GetTableName()
|
||||
return "Auth";
|
||||
}
|
||||
|
||||
template<>
|
||||
std::string DBUpdater<LoginDatabaseConnection>::GetSourceDirectory()
|
||||
{
|
||||
return BuiltInConfig::GetSourceDirectory();
|
||||
}
|
||||
|
||||
template<>
|
||||
std::string DBUpdater<LoginDatabaseConnection>::GetBaseFilesDirectory()
|
||||
{
|
||||
return BuiltInConfig::GetSourceDirectory() + "/data/sql/base/db_auth/";
|
||||
return DBUpdater<LoginDatabaseConnection>::GetSourceDirectory() + "/data/sql/base/db_auth/";
|
||||
}
|
||||
|
||||
template<>
|
||||
@@ -126,10 +133,16 @@ std::string DBUpdater<WorldDatabaseConnection>::GetTableName()
|
||||
return "World";
|
||||
}
|
||||
|
||||
template<>
|
||||
std::string DBUpdater<WorldDatabaseConnection>::GetSourceDirectory()
|
||||
{
|
||||
return BuiltInConfig::GetSourceDirectory();
|
||||
}
|
||||
|
||||
template<>
|
||||
std::string DBUpdater<WorldDatabaseConnection>::GetBaseFilesDirectory()
|
||||
{
|
||||
return BuiltInConfig::GetSourceDirectory() + "/data/sql/base/db_world/";
|
||||
return DBUpdater<WorldDatabaseConnection>::GetSourceDirectory() + "/data/sql/base/db_world/";
|
||||
}
|
||||
|
||||
template<>
|
||||
@@ -159,10 +172,16 @@ std::string DBUpdater<CharacterDatabaseConnection>::GetTableName()
|
||||
return "Character";
|
||||
}
|
||||
|
||||
template<>
|
||||
std::string DBUpdater<CharacterDatabaseConnection>::GetSourceDirectory()
|
||||
{
|
||||
return BuiltInConfig::GetSourceDirectory();
|
||||
}
|
||||
|
||||
template<>
|
||||
std::string DBUpdater<CharacterDatabaseConnection>::GetBaseFilesDirectory()
|
||||
{
|
||||
return BuiltInConfig::GetSourceDirectory() + "/data/sql/base/db_characters/";
|
||||
return DBUpdater<CharacterDatabaseConnection>::GetSourceDirectory() + "/data/sql/base/db_characters/";
|
||||
}
|
||||
|
||||
template<>
|
||||
@@ -186,8 +205,19 @@ BaseLocation DBUpdater<T>::GetBaseLocationType()
|
||||
return LOCATION_REPOSITORY;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool DBUpdater<T>::Create(DatabaseWorkerPool<T>& pool)
|
||||
namespace
|
||||
{
|
||||
|
||||
using Path = std::filesystem::path;
|
||||
|
||||
QueryResult Retrieve(DatabaseUpdatePool& pool, std::string const& query);
|
||||
void Apply(DatabaseUpdatePool& pool, std::string const& query);
|
||||
void ApplyFile(DatabaseUpdatePool& pool, Path const& path);
|
||||
void ApplyFile(DatabaseUpdatePool& pool, std::string const& host, std::string const& user,
|
||||
std::string const& password, std::string const& port_or_socket, std::string const& database,
|
||||
std::string const& ssl, Path const& path);
|
||||
|
||||
bool CreateDatabase(DatabaseUpdatePool& pool)
|
||||
{
|
||||
LOG_WARN("sql.updates", "Database \"{}\" does not exist", pool.GetConnectionInfo()->database);
|
||||
|
||||
@@ -220,8 +250,9 @@ bool DBUpdater<T>::Create(DatabaseWorkerPool<T>& pool)
|
||||
|
||||
try
|
||||
{
|
||||
DBUpdater<T>::ApplyFile(pool, pool.GetConnectionInfo()->host, pool.GetConnectionInfo()->user, pool.GetConnectionInfo()->password,
|
||||
pool.GetConnectionInfo()->port_or_socket, "", pool.GetConnectionInfo()->ssl, temp);
|
||||
ApplyFile(pool, pool.GetConnectionInfo()->host, pool.GetConnectionInfo()->user,
|
||||
pool.GetConnectionInfo()->password, pool.GetConnectionInfo()->port_or_socket, "",
|
||||
pool.GetConnectionInfo()->ssl, temp);
|
||||
}
|
||||
catch (UpdateException&)
|
||||
{
|
||||
@@ -236,15 +267,14 @@ bool DBUpdater<T>::Create(DatabaseWorkerPool<T>& pool)
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool DBUpdater<T>::Update(DatabaseWorkerPool<T>& pool, std::string_view modulesList /*= {}*/)
|
||||
bool UpdateDatabase(DatabaseUpdatePool& pool, DBUpdaterInfo const& info, std::string_view modulesList)
|
||||
{
|
||||
if (!DBUpdaterUtil::CheckExecutable())
|
||||
return false;
|
||||
|
||||
LOG_INFO("sql.updates", "Updating {} database...", DBUpdater<T>::GetTableName());
|
||||
LOG_INFO("sql.updates", "Updating {} database...", info.displayName);
|
||||
|
||||
Path const sourceDirectory(BuiltInConfig::GetSourceDirectory());
|
||||
Path const sourceDirectory(info.sourceDirectory);
|
||||
|
||||
if (!is_directory(sourceDirectory))
|
||||
{
|
||||
@@ -255,16 +285,16 @@ bool DBUpdater<T>::Update(DatabaseWorkerPool<T>& pool, std::string_view modulesL
|
||||
|
||||
auto CheckUpdateTable = [&](std::string const& tableName)
|
||||
{
|
||||
auto checkTable = DBUpdater<T>::Retrieve(pool, Acore::StringFormat("SHOW TABLES LIKE '{}'", tableName));
|
||||
auto checkTable = Retrieve(pool, Acore::StringFormat("SHOW TABLES LIKE '{}'", tableName));
|
||||
if (!checkTable)
|
||||
{
|
||||
LOG_WARN("sql.updates", "> Table '{}' not exist! Try add based table", tableName);
|
||||
|
||||
Path const temp(GetBaseFilesDirectory() + tableName + ".sql");
|
||||
Path const temp = Path(info.baseFilesDirectory) / (tableName + ".sql");
|
||||
|
||||
try
|
||||
{
|
||||
DBUpdater<T>::ApplyFile(pool, temp);
|
||||
ApplyFile(pool, temp);
|
||||
}
|
||||
catch (UpdateException&)
|
||||
{
|
||||
@@ -281,9 +311,9 @@ bool DBUpdater<T>::Update(DatabaseWorkerPool<T>& pool, std::string_view modulesL
|
||||
if (!CheckUpdateTable("updates") || !CheckUpdateTable("updates_include"))
|
||||
return false;
|
||||
|
||||
UpdateFetcher updateFetcher(sourceDirectory, [&](std::string const & query) { DBUpdater<T>::Apply(pool, query); },
|
||||
[&](Path const & file) { DBUpdater<T>::ApplyFile(pool, file); },
|
||||
[&](std::string const & query) -> QueryResult { return DBUpdater<T>::Retrieve(pool, query); }, DBUpdater<T>::GetDBModuleName(), modulesList);
|
||||
UpdateFetcher updateFetcher(sourceDirectory, [&](std::string const & query) { Apply(pool, query); },
|
||||
[&](Path const & file) { ApplyFile(pool, file); },
|
||||
[&](std::string const & query) -> QueryResult { return Retrieve(pool, query); }, info.dbModuleName, modulesList);
|
||||
|
||||
UpdateResult result;
|
||||
try
|
||||
@@ -299,27 +329,27 @@ bool DBUpdater<T>::Update(DatabaseWorkerPool<T>& pool, std::string_view modulesL
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string const info = Acore::StringFormat("Containing {} new and {} archived updates.", result.recent, result.archived);
|
||||
std::string const summary = Acore::StringFormat("Containing {} new and {} archived updates.", result.recent, result.archived);
|
||||
|
||||
if (!result.updated)
|
||||
LOG_INFO("sql.updates", ">> {} database is up-to-date! {}", DBUpdater<T>::GetTableName(), info);
|
||||
LOG_INFO("sql.updates", ">> {} database is up-to-date! {}", info.displayName, summary);
|
||||
else
|
||||
LOG_INFO("sql.updates", ">> Applied {} {}. {}", result.updated, result.updated == 1 ? "query" : "queries", info);
|
||||
LOG_INFO("sql.updates", ">> Applied {} {}. {}", result.updated, result.updated == 1 ? "query" : "queries", summary);
|
||||
|
||||
LOG_INFO("sql.updates", " ");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool DBUpdater<T>::Update(DatabaseWorkerPool<T>& pool, std::vector<std::string> const* setDirectories)
|
||||
bool UpdateDatabase(DatabaseUpdatePool& pool, DBUpdaterInfo const& info,
|
||||
std::vector<std::string> const* setDirectories)
|
||||
{
|
||||
if (!DBUpdaterUtil::CheckExecutable())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Path const sourceDirectory(BuiltInConfig::GetSourceDirectory());
|
||||
Path const sourceDirectory(info.sourceDirectory);
|
||||
if (!is_directory(sourceDirectory))
|
||||
{
|
||||
return false;
|
||||
@@ -327,13 +357,13 @@ bool DBUpdater<T>::Update(DatabaseWorkerPool<T>& pool, std::vector<std::string>
|
||||
|
||||
auto CheckUpdateTable = [&](std::string const& tableName)
|
||||
{
|
||||
auto checkTable = DBUpdater<T>::Retrieve(pool, Acore::StringFormat("SHOW TABLES LIKE '{}'", tableName));
|
||||
auto checkTable = Retrieve(pool, Acore::StringFormat("SHOW TABLES LIKE '{}'", tableName));
|
||||
if (!checkTable)
|
||||
{
|
||||
Path const temp(GetBaseFilesDirectory() + tableName + ".sql");
|
||||
Path const temp = Path(info.baseFilesDirectory) / (tableName + ".sql");
|
||||
try
|
||||
{
|
||||
DBUpdater<T>::ApplyFile(pool, temp);
|
||||
ApplyFile(pool, temp);
|
||||
}
|
||||
catch (UpdateException&)
|
||||
{
|
||||
@@ -351,9 +381,9 @@ bool DBUpdater<T>::Update(DatabaseWorkerPool<T>& pool, std::vector<std::string>
|
||||
return false;
|
||||
}
|
||||
|
||||
UpdateFetcher updateFetcher(sourceDirectory, [&](std::string const & query) { DBUpdater<T>::Apply(pool, query); },
|
||||
[&](Path const & file) { DBUpdater<T>::ApplyFile(pool, file); },
|
||||
[&](std::string const & query) -> QueryResult { return DBUpdater<T>::Retrieve(pool, query); }, DBUpdater<T>::GetDBModuleName(), setDirectories);
|
||||
UpdateFetcher updateFetcher(sourceDirectory, [&](std::string const & query) { Apply(pool, query); },
|
||||
[&](Path const & file) { ApplyFile(pool, file); },
|
||||
[&](std::string const & query) -> QueryResult { return Retrieve(pool, query); }, info.dbModuleName, setDirectories);
|
||||
|
||||
UpdateResult result;
|
||||
try
|
||||
@@ -372,8 +402,7 @@ bool DBUpdater<T>::Update(DatabaseWorkerPool<T>& pool, std::vector<std::string>
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool DBUpdater<T>::Populate(DatabaseWorkerPool<T>& pool)
|
||||
bool PopulateDatabase(DatabaseUpdatePool& pool, DBUpdaterInfo const& info)
|
||||
{
|
||||
{
|
||||
QueryResult const result = Retrieve(pool, "SHOW TABLES");
|
||||
@@ -384,9 +413,9 @@ bool DBUpdater<T>::Populate(DatabaseWorkerPool<T>& pool)
|
||||
if (!DBUpdaterUtil::CheckExecutable())
|
||||
return false;
|
||||
|
||||
LOG_INFO("sql.updates", "Database {} is empty, auto populating it...", DBUpdater<T>::GetTableName());
|
||||
LOG_INFO("sql.updates", "Database {} is empty, auto populating it...", info.displayName);
|
||||
|
||||
std::string const DirPathStr = DBUpdater<T>::GetBaseFilesDirectory();
|
||||
std::string const DirPathStr = info.baseFilesDirectory;
|
||||
|
||||
Path const DirPath(DirPathStr);
|
||||
if (!std::filesystem::is_directory(DirPath))
|
||||
@@ -445,28 +474,26 @@ bool DBUpdater<T>::Populate(DatabaseWorkerPool<T>& pool)
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
QueryResult DBUpdater<T>::Retrieve(DatabaseWorkerPool<T>& pool, std::string const& query)
|
||||
QueryResult Retrieve(DatabaseUpdatePool& pool, std::string const& query)
|
||||
{
|
||||
return pool.Query(query.c_str());
|
||||
return pool.Query(query);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void DBUpdater<T>::Apply(DatabaseWorkerPool<T>& pool, std::string const& query)
|
||||
void Apply(DatabaseUpdatePool& pool, std::string const& query)
|
||||
{
|
||||
pool.DirectExecute(query.c_str());
|
||||
pool.DirectExecute(query);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void DBUpdater<T>::ApplyFile(DatabaseWorkerPool<T>& pool, Path const& path)
|
||||
void ApplyFile(DatabaseUpdatePool& pool, Path const& path)
|
||||
{
|
||||
DBUpdater<T>::ApplyFile(pool, pool.GetConnectionInfo()->host, pool.GetConnectionInfo()->user, pool.GetConnectionInfo()->password,
|
||||
pool.GetConnectionInfo()->port_or_socket, pool.GetConnectionInfo()->database, pool.GetConnectionInfo()->ssl, path);
|
||||
ApplyFile(pool, pool.GetConnectionInfo()->host, pool.GetConnectionInfo()->user,
|
||||
pool.GetConnectionInfo()->password, pool.GetConnectionInfo()->port_or_socket,
|
||||
pool.GetConnectionInfo()->database, pool.GetConnectionInfo()->ssl, path);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void DBUpdater<T>::ApplyFile(DatabaseWorkerPool<T>& pool, std::string const& host, std::string const& user,
|
||||
std::string const& password, std::string const& port_or_socket, std::string const& database, std::string const& ssl, Path const& path)
|
||||
void ApplyFile(DatabaseUpdatePool& pool, std::string const& host, std::string const& user,
|
||||
std::string const& password, std::string const& port_or_socket, std::string const& database,
|
||||
std::string const& ssl, Path const& path)
|
||||
{
|
||||
std::string configTempDir = sConfigMgr->GetOption<std::string>("TempDir", "");
|
||||
|
||||
@@ -554,6 +581,58 @@ void DBUpdater<T>::ApplyFile(DatabaseWorkerPool<T>& pool, std::string const& hos
|
||||
}
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
template<class T>
|
||||
DBUpdaterInfo DBUpdater<T>::GetUpdaterInfo()
|
||||
{
|
||||
return { GetTableName(), GetSourceDirectory(), GetBaseFilesDirectory(), GetDBModuleName() };
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool DBUpdater<T>::Create(DatabaseWorkerPool<T>& pool)
|
||||
{
|
||||
DatabaseWorkerPoolAdapter<T> adapter(pool);
|
||||
return CreateDatabase(adapter);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool DBUpdater<T>::Update(DatabaseWorkerPool<T>& pool, std::string_view modulesList /*= {}*/)
|
||||
{
|
||||
DatabaseWorkerPoolAdapter<T> adapter(pool);
|
||||
return UpdateDatabase(adapter, GetUpdaterInfo(), modulesList);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool DBUpdater<T>::Update(DatabaseWorkerPool<T>& pool, std::vector<std::string> const* setDirectories)
|
||||
{
|
||||
DatabaseWorkerPoolAdapter<T> adapter(pool);
|
||||
return UpdateDatabase(adapter, GetUpdaterInfo(), setDirectories);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool DBUpdater<T>::Populate(DatabaseWorkerPool<T>& pool)
|
||||
{
|
||||
DatabaseWorkerPoolAdapter<T> adapter(pool);
|
||||
return PopulateDatabase(adapter, GetUpdaterInfo());
|
||||
}
|
||||
|
||||
bool ModuleDBUpdater::Create(DatabaseUpdatePool& pool)
|
||||
{
|
||||
return CreateDatabase(pool);
|
||||
}
|
||||
|
||||
bool ModuleDBUpdater::Update(DatabaseUpdatePool& pool, DBUpdaterInfo const& info,
|
||||
std::string_view modulesList /*= {}*/)
|
||||
{
|
||||
return UpdateDatabase(pool, info, modulesList);
|
||||
}
|
||||
|
||||
bool ModuleDBUpdater::Populate(DatabaseUpdatePool& pool, DBUpdaterInfo const& info)
|
||||
{
|
||||
return PopulateDatabase(pool, info);
|
||||
}
|
||||
|
||||
template class AC_DATABASE_API DBUpdater<LoginDatabaseConnection>;
|
||||
template class AC_DATABASE_API DBUpdater<WorldDatabaseConnection>;
|
||||
template class AC_DATABASE_API DBUpdater<CharacterDatabaseConnection>;
|
||||
|
||||
@@ -19,13 +19,13 @@
|
||||
#define DBUpdater_h__
|
||||
|
||||
#include "DatabaseEnv.h"
|
||||
#include "DatabaseUpdatePool.h"
|
||||
#include "Define.h"
|
||||
#include "QueryResult.h"
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
|
||||
template <class T>
|
||||
class DatabaseWorkerPool;
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
@@ -71,6 +71,15 @@ private:
|
||||
static uint32& failed_updates();
|
||||
};
|
||||
|
||||
// Runtime metadata the updater needs about one database, core or module owned.
|
||||
struct DBUpdaterInfo
|
||||
{
|
||||
std::string displayName; // name used in log output
|
||||
std::string sourceDirectory; // root directory holding the sql tree
|
||||
std::string baseFilesDirectory; // base *.sql files, trailing separator optional
|
||||
std::string dbModuleName; // update-fetcher module name, must be lowercase
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class AC_DATABASE_API DBUpdater
|
||||
{
|
||||
@@ -79,6 +88,7 @@ public:
|
||||
|
||||
static inline std::string GetConfigEntry();
|
||||
static inline std::string GetTableName();
|
||||
static std::string GetSourceDirectory();
|
||||
static std::string GetBaseFilesDirectory();
|
||||
static bool IsEnabled(uint32 const updateMask);
|
||||
static BaseLocation GetBaseLocationType();
|
||||
@@ -91,11 +101,18 @@ public:
|
||||
static std::string GetDBModuleName();
|
||||
|
||||
private:
|
||||
static QueryResult Retrieve(DatabaseWorkerPool<T>& pool, std::string const& query);
|
||||
static void Apply(DatabaseWorkerPool<T>& pool, std::string const& query);
|
||||
static void ApplyFile(DatabaseWorkerPool<T>& pool, Path const& path);
|
||||
static void ApplyFile(DatabaseWorkerPool<T>& pool, std::string const& host, std::string const& user,
|
||||
std::string const& password, std::string const& port_or_socket, std::string const& database, std::string const& ssl, Path const& path);
|
||||
static DBUpdaterInfo GetUpdaterInfo();
|
||||
};
|
||||
|
||||
// Non-template updater entry points for module-owned pools (see ModuleDatabasePool).
|
||||
// Mirrors the DBUpdater<T> flow: Create the schema when missing, Populate an empty
|
||||
// database from the base files, then apply pending updates through the UpdateFetcher.
|
||||
class AC_DATABASE_API ModuleDBUpdater
|
||||
{
|
||||
public:
|
||||
static bool Create(DatabaseUpdatePool& pool);
|
||||
static bool Update(DatabaseUpdatePool& pool, DBUpdaterInfo const& info, std::string_view modulesList = {});
|
||||
static bool Populate(DatabaseUpdatePool& pool, DBUpdaterInfo const& info);
|
||||
};
|
||||
|
||||
#endif // DBUpdater_h__
|
||||
|
||||
@@ -19,6 +19,11 @@
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptMgrMacros.h"
|
||||
|
||||
bool ScriptMgr::OnModuleDatabasesLoading()
|
||||
{
|
||||
CALL_ENABLED_BOOLEAN_HOOKS(DatabaseScript, DATABASEHOOK_ON_MODULE_DATABASES_LOADING, !script->OnModuleDatabasesLoading());
|
||||
}
|
||||
|
||||
void ScriptMgr::OnAfterDatabasesLoaded(uint32 updateFlags)
|
||||
{
|
||||
CALL_ENABLED_HOOKS(DatabaseScript, DATABASEHOOK_ON_AFTER_DATABASES_LOADED, script->OnAfterDatabasesLoaded(updateFlags));
|
||||
@@ -29,6 +34,26 @@ void ScriptMgr::OnAfterDatabaseLoadCreatureTemplates(std::vector<CreatureTemplat
|
||||
CALL_ENABLED_HOOKS(DatabaseScript, DATABASEHOOK_ON_AFTER_DATABASE_LOAD_CREATURETEMPLATES, script->OnAfterDatabaseLoadCreatureTemplates(creatureTemplates));
|
||||
}
|
||||
|
||||
void ScriptMgr::OnModuleDatabasesKeepAlive()
|
||||
{
|
||||
CALL_ENABLED_HOOKS(DatabaseScript, DATABASEHOOK_ON_MODULE_DATABASES_KEEPALIVE, script->OnModuleDatabasesKeepAlive());
|
||||
}
|
||||
|
||||
void ScriptMgr::OnModuleDatabasesClosing()
|
||||
{
|
||||
CALL_ENABLED_HOOKS(DatabaseScript, DATABASEHOOK_ON_MODULE_DATABASES_CLOSING, script->OnModuleDatabasesClosing());
|
||||
}
|
||||
|
||||
void ScriptMgr::OnDatabaseWarnAboutSyncQueries(bool apply)
|
||||
{
|
||||
CALL_ENABLED_HOOKS(DatabaseScript, DATABASEHOOK_ON_DATABASE_WARN_ABOUT_SYNC_QUERIES, script->OnDatabaseWarnAboutSyncQueries(apply));
|
||||
}
|
||||
|
||||
void ScriptMgr::OnDatabaseGetDBRevision(std::map<std::string, std::string>& revisions)
|
||||
{
|
||||
CALL_ENABLED_HOOKS(DatabaseScript, DATABASEHOOK_ON_DATABASE_GET_DB_REVISION, script->OnDatabaseGetDBRevision(revisions));
|
||||
}
|
||||
|
||||
DatabaseScript::DatabaseScript(char const* name, std::vector<uint16> enabledHooks)
|
||||
: ScriptObject(name, DATABASEHOOK_END)
|
||||
{
|
||||
|
||||
@@ -19,12 +19,19 @@
|
||||
#define SCRIPT_OBJECT_DATABASE_SCRIPT_H_
|
||||
|
||||
#include "ScriptObject.h"
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
enum DatabaseHook
|
||||
{
|
||||
DATABASEHOOK_ON_AFTER_DATABASES_LOADED,
|
||||
DATABASEHOOK_ON_AFTER_DATABASE_LOAD_CREATURETEMPLATES,
|
||||
DATABASEHOOK_ON_MODULE_DATABASES_LOADING,
|
||||
DATABASEHOOK_ON_MODULE_DATABASES_KEEPALIVE,
|
||||
DATABASEHOOK_ON_MODULE_DATABASES_CLOSING,
|
||||
DATABASEHOOK_ON_DATABASE_WARN_ABOUT_SYNC_QUERIES,
|
||||
DATABASEHOOK_ON_DATABASE_GET_DB_REVISION,
|
||||
DATABASEHOOK_END
|
||||
};
|
||||
|
||||
@@ -52,6 +59,38 @@ public:
|
||||
*/
|
||||
virtual void OnAfterDatabaseLoadCreatureTemplates(std::vector<CreatureTemplate*> /*creatureTemplates*/) { }
|
||||
|
||||
/**
|
||||
* @brief Called once the core databases are up, so a module can open a database of its own.
|
||||
* Runs before the rest of the world loads, unlike OnAfterDatabasesLoaded which reports the
|
||||
* finished core load.
|
||||
*
|
||||
* @return false to abort startup, e.g. when the module's own database failed to open
|
||||
*/
|
||||
[[nodiscard]] virtual bool OnModuleDatabasesLoading() { return true; }
|
||||
|
||||
/**
|
||||
* @brief Called on the world's keep-alive tick, alongside the core pools being pinged.
|
||||
*/
|
||||
virtual void OnModuleDatabasesKeepAlive() { }
|
||||
|
||||
/**
|
||||
* @brief Called after the core databases are closed, so a module can close its own.
|
||||
*/
|
||||
virtual void OnModuleDatabasesClosing() { }
|
||||
|
||||
/**
|
||||
* @brief Called when the core turns its synchronous-query warning on or off.
|
||||
*
|
||||
* @param apply True when the warning is being enabled
|
||||
*/
|
||||
virtual void OnDatabaseWarnAboutSyncQueries(bool /*apply*/) { }
|
||||
|
||||
/**
|
||||
* @brief Called by .server info to collect the revision of a module-owned database.
|
||||
*
|
||||
* @param revisions Revision string to report, keyed by module name
|
||||
*/
|
||||
virtual void OnDatabaseGetDBRevision(std::map<std::string, std::string>& /*revisions*/) { }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -712,8 +712,13 @@ public: /* CommandSC */
|
||||
|
||||
public: /* DatabaseScript */
|
||||
|
||||
bool OnModuleDatabasesLoading();
|
||||
void OnAfterDatabasesLoaded(uint32 updateFlags);
|
||||
void OnAfterDatabaseLoadCreatureTemplates(std::vector<CreatureTemplate*> creatureTemplateStore);
|
||||
void OnModuleDatabasesKeepAlive();
|
||||
void OnModuleDatabasesClosing();
|
||||
void OnDatabaseWarnAboutSyncQueries(bool apply);
|
||||
void OnDatabaseGetDBRevision(std::map<std::string, std::string>& revisions);
|
||||
|
||||
public: /* WorldObjectScript */
|
||||
|
||||
|
||||
@@ -1322,6 +1322,7 @@ void World::Update(uint32 diff)
|
||||
CharacterDatabase.KeepAlive();
|
||||
LoginDatabase.KeepAlive();
|
||||
WorldDatabase.KeepAlive();
|
||||
sScriptMgr->OnModuleDatabasesKeepAlive();
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "MySQLThreading.h"
|
||||
#include "RBAC.h"
|
||||
#include "Realm.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "StringConvert.h"
|
||||
#include "UpdateTime.h"
|
||||
#include "VMapFactory.h"
|
||||
@@ -34,6 +35,7 @@
|
||||
#include "WorldSessionMgr.h"
|
||||
#include <boost/version.hpp>
|
||||
#include <filesystem>
|
||||
#include <map>
|
||||
#include <numeric>
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/opensslv.h>
|
||||
@@ -216,6 +218,11 @@ public:
|
||||
|
||||
handler->PSendSysMessage("Using World DB: {}", sWorld->GetDBVersion());
|
||||
|
||||
std::map<std::string, std::string> moduleDBRevisions;
|
||||
sScriptMgr->OnDatabaseGetDBRevision(moduleDBRevisions);
|
||||
for (auto const& [moduleName, revision] : moduleDBRevisions)
|
||||
handler->PSendSysMessage("Using {} DB Revision: {}", moduleName, revision);
|
||||
|
||||
std::string lldb = "No updates found!";
|
||||
if (QueryResult resL = LoginDatabase.Query("SELECT name FROM updates ORDER BY name DESC LIMIT 1"))
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user