35#include <mysqld_error.h>
38#include <boost/stacktrace.hpp>
46 for (std::size_t i = 0; i < chars.length(); ++i)
52 throw "Too many . characters in version string";
54 result += partialResult * multiplier;
58 else if (c >=
'0' && c <=
'9')
61 partialResult += c -
'0';
64 throw "Invalid input character";
67 result += partialResult * multiplier;
85 _async_threads(0), _synch_threads(0)
90#if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS
91#if defined(LIBMARIADB) && MARIADB_PACKAGE_VERSION_ID >= 30200
92#define TRINITY_COMPILED_CLIENT_VERSION MARIADB_PACKAGE_VERSION_ID
94#define TRINITY_COMPILED_CLIENT_VERSION MYSQL_VERSION_ID
97#undef TRINITY_COMPILED_CLIENT_VERSION
109 uint8 const asyncThreads,
uint8 const synchThreads)
111 _connectionInfo = std::make_unique<MySQLConnectionInfo>(infoString);
113 _async_threads = asyncThreads;
114 _synch_threads = synchThreads;
120 WPFatal(_connectionInfo.get(),
"Connection info was not set!");
122 TC_LOG_INFO(
"sql.driver",
"Opening DatabasePool '{}'. "
123 "Asynchronous connections: {}, synchronous connections: {}.",
124 GetDatabaseName(), _async_threads, _synch_threads);
126 uint32 error = OpenConnections(IDX_ASYNC, _async_threads);
131 error = OpenConnections(IDX_SYNCH, _synch_threads);
135 TC_LOG_INFO(
"sql.driver",
"DatabasePool '{}' opened successfully. "
136 "{} total connections running.", GetDatabaseName(),
137 (_connections[IDX_SYNCH].size() + _connections[IDX_ASYNC].size()));
146 TC_LOG_INFO(
"sql.driver",
"Closing down DatabasePool '{}'.", GetDatabaseName());
149 _connections[IDX_ASYNC].clear();
151 TC_LOG_INFO(
"sql.driver",
"Asynchronous connections on DatabasePool '{}' terminated. "
152 "Proceeding with synchronous connections.",
159 _connections[IDX_SYNCH].clear();
161 TC_LOG_INFO(
"sql.driver",
"All connections on DatabasePool '{}' closed.", GetDatabaseName());
167 for (
auto& connections : _connections)
169 for (
auto& connection : connections)
171 connection->LockIfReady();
172 if (!connection->PrepareStatements())
174 connection->Unlock();
179 connection->Unlock();
181 size_t const preparedSize = connection->m_stmts.size();
182 if (_preparedStatementSize.size() < preparedSize)
183 _preparedStatementSize.resize(preparedSize);
185 for (
size_t i = 0; i < preparedSize; ++i)
189 if (_preparedStatementSize[i] > 0)
194 uint32 const paramCount = stmt->GetParameterCount();
197 ASSERT(paramCount < std::numeric_limits<uint8>::max());
199 _preparedStatementSize[i] =
static_cast<uint8>(paramCount);
212 connection = GetFreeConnection();
214 ResultSet* result = connection->Query(sql);
215 connection->Unlock();
228 auto connection = GetFreeConnection();
230 connection->Unlock();
271 return { std::move(holder), std::move(result) };
277 return std::make_shared<Transaction<T>>();
287 switch (transaction->GetSize())
290 TC_LOG_DEBUG(
"sql.driver",
"Transaction contains 0 queries. Not executing.");
293 TC_LOG_DEBUG(
"sql.driver",
"Warning: Transaction only holds 1 query, consider removing Transaction context in code.");
310 switch (transaction->GetSize())
313 TC_LOG_DEBUG(
"sql.driver",
"Transaction contains 0 queries. Not executing.");
316 TC_LOG_DEBUG(
"sql.driver",
"Warning: Transaction only holds 1 query, consider removing Transaction context in code.");
332 T* connection = GetFreeConnection();
333 int errorCode = connection->ExecuteTransaction(transaction);
336 connection->Unlock();
342 if (errorCode == ER_LOCK_DEADLOCK)
345 uint8 loopBreaker = 5;
346 for (
uint8 i = 0; i < loopBreaker; ++i)
348 if (!connection->ExecuteTransaction(transaction))
354 transaction->Cleanup();
356 connection->Unlock();
371 char* buf =
new char[str.size() * 2 + 1];
372 EscapeString(buf, str.c_str(),
uint32(str.size()));
381 for (
auto& connection : _connections[IDX_SYNCH])
383 if (connection->LockIfReady())
386 connection->Unlock();
393 auto const count = _connections[IDX_ASYNC].size();
394 for (
uint8 i = 0; i < count; ++i)
401 for (
uint8 i = 0; i < numConnections; ++i)
404 auto connection = [&] {
408 return std::make_unique<T>(_queue.get(), *_connectionInfo);
410 return std::make_unique<T>(*_connectionInfo);
416 if (
uint32 error = connection->Open())
419 _connections[type].clear();
422 else if (
uint32 serverVersion = connection->GetServerVersion(); serverVersion <
ParseVersionString(TRINITY_REQUIRED_MYSQL_VERSION))
424 TC_LOG_ERROR(
"sql.driver",
"TrinityCore does not support " TRINITY_MYSQL_FLAVOR
" versions below " TRINITY_REQUIRED_MYSQL_VERSION
" (found id {}, need id >= {}), please update your " TRINITY_MYSQL_FLAVOR
" server", serverVersion,
ParseVersionString(TRINITY_REQUIRED_MYSQL_VERSION));
429 _connections[type].push_back(std::move(connection));
440 if (!to || !from || !length)
443 return _connections[IDX_SYNCH].front()->EscapeString(to, from, length);
455 return _queue->Size();
462 if (_warnSyncQueries)
464 std::ostringstream ss;
465 ss << boost::stacktrace::stacktrace();
466 TC_LOG_WARN(
"sql.performances",
"Sync query at:\n{}", ss.str());
471 auto const num_cons = _connections[IDX_SYNCH].size();
472 T* connection =
nullptr;
476 connection = _connections[IDX_SYNCH][++i % num_cons].get();
478 if (connection->LockIfReady())
488 return _connectionInfo->database.c_str();
514 T* connection = GetFreeConnection();
515 connection->Execute(sql);
516 connection->Unlock();
522 T* connection = GetFreeConnection();
523 connection->Execute(stmt);
524 connection->Unlock();
std::future< PreparedQueryResult > PreparedQueryResultFuture
std::future< QueryResult > QueryResultFuture
std::shared_ptr< ResultSet > QueryResult
std::shared_ptr< Transaction< T > > SQLTransaction
std::shared_ptr< PreparedResultSet > PreparedQueryResult
std::future< bool > TransactionFuture
std::future< void > QueryResultHolderFuture
static consteval uint32 ParseVersionString(std::string_view chars)
#define TRINITY_COMPILED_CLIENT_VERSION
#define WPFatal(cond,...)
#define TC_LOG_WARN(filterType__,...)
#define TC_LOG_DEBUG(filterType__,...)
#define TC_LOG_ERROR(filterType__,...)
#define TC_LOG_INFO(filterType__,...)
QueryResultFuture GetFuture() const
uint32 OpenConnections(InternalIndex type, uint8 numConnections)
void CommitTransaction(SQLTransaction< T > transaction)
void Enqueue(SQLOperation *op)
QueryResult Query(char const *sql, T *connection=nullptr)
bool PrepareStatements()
Prepares all prepared statements.
void SetConnectionInfo(std::string const &infoString, uint8 const asyncThreads, uint8 const synchThreads)
void ExecuteOrAppend(SQLTransaction< T > &trans, char const *sql)
SQLTransaction< T > BeginTransaction()
Begins an automanaged transaction pointer that will automatically rollback if not commited....
void DirectCommitTransaction(SQLTransaction< T > &transaction)
void KeepAlive()
Keeps all our MySQL connections alive, prevent the server from disconnecting us.
T::Statements PreparedStatementIndex
char const * GetDatabaseName() const
PreparedStatement< T > * GetPreparedStatement(PreparedStatementIndex index)
void DirectExecute(char const *sql)
SQLQueryHolderCallback DelayQueryHolder(std::shared_ptr< SQLQueryHolder< T > > holder)
void EscapeString(std::string &str)
Apply escape string'ing for current collation. (utf8)
void Execute(char const *sql)
QueryCallback AsyncQuery(char const *sql)
TransactionCallback AsyncCommitTransaction(SQLTransaction< T > transaction)
bool Execute() override
Operation for idle delaythreads.
uint64 GetRowCount() const
PreparedQueryResultFuture GetFuture()
uint64 GetRowCount() const
QueryResultHolderFuture GetFuture()
TransactionFuture GetFuture()
bool IsFormatEmptyOrNull(char const *fmt)
Returns true if the given char pointer is null.