TrinityCore
MySQLConnection.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "MySQLConnection.h"
19#include "Common.h"
20#include "IoContext.h"
21#include "Log.h"
22#include "MySQLHacks.h"
24#include "PreparedStatement.h"
25#include "QueryResult.h"
26#include "StringConvert.h"
27#include "Timer.h"
28#include "Transaction.h"
29#include "Util.h"
30#include <errmsg.h>
31#include "MySQLWorkaround.h"
32#include <mysqld_error.h>
33
34MySQLConnectionInfo::MySQLConnectionInfo(std::string const& infoString)
35{
36 std::vector<std::string_view> tokens = Trinity::Tokenize(infoString, ';', true);
37
38 if (tokens.size() != 5 && tokens.size() != 6)
39 return;
40
41 host.assign(tokens[0]);
42 port_or_socket.assign(tokens[1]);
43 user.assign(tokens[2]);
44 password.assign(tokens[3]);
45 database.assign(tokens[4]);
46
47 if (tokens.size() == 6)
48 ssl.assign(tokens[5]);
49}
50
52{
53 std::thread ThreadHandle;
54 boost::asio::executor_work_guard<Trinity::Asio::IoContext::Executor> WorkGuard;
55};
56
58m_reconnecting(false),
59m_prepareError(false),
60m_Mysql(nullptr),
61m_connectionInfo(connInfo),
62m_connectionFlags(connectionFlags)
63{
64}
65
67{
68 Close();
69}
70
72{
73 // Stop the worker thread before the statements are cleared
75 {
76 m_workerThread->WorkGuard.reset();
77 m_workerThread->ThreadHandle.join();
78 m_workerThread.reset();
79 }
80
81 m_stmts.clear();
82
83 if (m_Mysql)
84 {
85 mysql_close(m_Mysql);
86 m_Mysql = nullptr;
87 }
88}
89
91{
92 MYSQL *mysqlInit;
93 mysqlInit = mysql_init(nullptr);
94 if (!mysqlInit)
95 {
96 TC_LOG_ERROR("sql.sql", "Could not initialize Mysql connection to database `{}`", m_connectionInfo.database);
97 return CR_UNKNOWN_ERROR;
98 }
99
100 int port = 0;
101 char const* unix_socket = nullptr;
102 //unsigned int timeout = 10;
103
104 mysql_options(mysqlInit, MYSQL_SET_CHARSET_NAME, "utf8mb4");
105 //mysql_options(mysqlInit, MYSQL_OPT_READ_TIMEOUT, (char const*)&timeout);
106 if (m_connectionInfo.host != ".")
107 {
108 port = Trinity::StringTo<int32>(m_connectionInfo.port_or_socket).value_or(0);
109 }
110 else // named pipe/unix socket option
111 {
112#if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS
113 unsigned int opt = MYSQL_PROTOCOL_PIPE;
114#else
115 m_connectionInfo.host = "localhost";
116 unix_socket = m_connectionInfo.port_or_socket.c_str();
117 unsigned int opt = MYSQL_PROTOCOL_SOCKET;
118#endif
119 mysql_options(mysqlInit, MYSQL_OPT_PROTOCOL, (char const*)&opt);
120
121#if !defined(MARIADB_VERSION_ID) && MYSQL_VERSION_ID >= 80000
122 /*
123 ensure connections over named pipes work for users authenticating with caching_sha2_password
124
125 If the mysql server is restarted, and you connect it using named pipe, the connection will fail and it will continue to fail until you connect it using tcp.
126 Source: https://bugs.mysql.com/bug.php?id=106852
127 */
128 MySQLBool geterverPublicKey = MySQLBool(1);
129 mysql_options(mysqlInit, MYSQL_OPT_GET_SERVER_PUBLIC_KEY, (char const*)&geterverPublicKey);
130#endif
131 }
132
133 if (!m_connectionInfo.ssl.empty())
134 {
135#if !defined(MARIADB_VERSION_ID) && MYSQL_VERSION_ID >= 80000
136 mysql_ssl_mode opt_use_ssl = SSL_MODE_DISABLED;
137 if (m_connectionInfo.ssl == "ssl")
138 {
139 opt_use_ssl = SSL_MODE_REQUIRED;
140 }
141 mysql_options(mysqlInit, MYSQL_OPT_SSL_MODE, (char const*)&opt_use_ssl);
142#else
143 MySQLBool opt_use_ssl = MySQLBool(0);
144 if (m_connectionInfo.ssl == "ssl")
145 {
146 opt_use_ssl = MySQLBool(1);
147 }
148 mysql_options(mysqlInit, MYSQL_OPT_SSL_ENFORCE, (char const*)&opt_use_ssl);
149#endif
150 }
151
152 m_Mysql = reinterpret_cast<MySQLHandle*>(mysql_real_connect(mysqlInit, m_connectionInfo.host.c_str(), m_connectionInfo.user.c_str(),
153 m_connectionInfo.password.c_str(), m_connectionInfo.database.c_str(), port, unix_socket, 0));
154
155 if (m_Mysql)
156 {
157 if (!m_reconnecting)
158 {
159 TC_LOG_INFO("sql.sql", "MySQL client library: {}", mysql_get_client_info());
160 TC_LOG_INFO("sql.sql", "MySQL server ver: {} ", mysql_get_server_info(m_Mysql));
161 // MySQL version above 5.1 IS required in both client and server and there is no known issue with different versions above 5.1
162 // if (mysql_get_server_version(m_Mysql) != mysql_get_client_version())
163 // TC_LOG_INFO("sql.sql", "[WARNING] MySQL client/server version mismatch; may conflict with behaviour of prepared statements.");
164 }
165
166 TC_LOG_INFO("sql.sql", "Connected to MySQL database at {}", m_connectionInfo.host);
167 mysql_autocommit(m_Mysql, 1);
168
169 // set connection properties to UTF8 to properly handle locales for different
170 // server configs - core sends data in UTF8, so MySQL must expect UTF8 too
171 mysql_set_character_set(m_Mysql, "utf8mb4");
172 return 0;
173 }
174 else
175 {
176 TC_LOG_ERROR("sql.sql", "Could not connect to MySQL database at {}: {}", m_connectionInfo.host, mysql_error(mysqlInit));
177 uint32 errorCode = mysql_errno(mysqlInit);
178 mysql_close(mysqlInit);
179 return errorCode;
180 }
181}
182
184{
186 return !m_prepareError;
187}
188
189bool MySQLConnection::Execute(char const* sql)
190{
191 if (!m_Mysql)
192 return false;
193
194 {
195 uint32 _s = getMSTime();
196
197 if (mysql_query(m_Mysql, sql))
198 {
199 uint32 lErrno = mysql_errno(m_Mysql);
200
201 TC_LOG_INFO("sql.sql", "SQL: {}", sql);
202 TC_LOG_ERROR("sql.sql", "[{}] {}", lErrno, mysql_error(m_Mysql));
203
204 if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection)
205 return Execute(sql); // Try again
206
207 return false;
208 }
209 else
210 TC_LOG_DEBUG("sql.sql", "[{} ms] SQL: {}", getMSTimeDiff(_s, getMSTime()), sql);
211 }
212
213 return true;
214}
215
216static auto mysql_bind_param_no_deprecated(MYSQL_STMT* stmt, MYSQL_BIND* bnd)
217{
218#if TRINITY_COMPILER == TRINITY_COMPILER_GNU
219#pragma GCC diagnostic push
220#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
221#else
222#pragma warning(push)
223#pragma warning(disable: 4996)
224#endif
225
226 return mysql_stmt_bind_param(stmt, bnd);
227
228#if TRINITY_COMPILER == TRINITY_COMPILER_GNU
229#pragma GCC diagnostic pop
230#else
231#pragma warning(pop)
232#endif
233}
234
236{
237 if (!m_Mysql)
238 return false;
239
240 uint32 index = stmt->GetIndex();
241
243 ASSERT(m_mStmt); // Can only be null if preparation failed, server side error or bad query
244
245 m_mStmt->BindParameters(stmt);
246
247 MYSQL_STMT* msql_STMT = m_mStmt->GetSTMT();
248 MYSQL_BIND* msql_BIND = m_mStmt->GetBind();
249
250 uint32 _s = getMSTime();
251
252 if (mysql_bind_param_no_deprecated(msql_STMT, msql_BIND))
253 {
254 uint32 lErrno = mysql_errno(m_Mysql);
255 TC_LOG_ERROR("sql.sql", "SQL(p): {}\n [ERROR]: [{}] {}", m_mStmt->getQueryString(), lErrno, mysql_stmt_error(msql_STMT));
256
257 if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection)
258 return Execute(stmt); // Try again
259
260 m_mStmt->ClearParameters();
261 return false;
262 }
263
264 if (mysql_stmt_execute(msql_STMT))
265 {
266 uint32 lErrno = mysql_errno(m_Mysql);
267 TC_LOG_ERROR("sql.sql", "SQL(p): {}\n [ERROR]: [{}] {}", m_mStmt->getQueryString(), lErrno, mysql_stmt_error(msql_STMT));
268
269 if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection)
270 return Execute(stmt); // Try again
271
272 m_mStmt->ClearParameters();
273 return false;
274 }
275
276 TC_LOG_DEBUG("sql.sql", "[{} ms] SQL(p): {}", getMSTimeDiff(_s, getMSTime()), m_mStmt->getQueryString());
277
278 m_mStmt->ClearParameters();
279 return true;
280}
281
282bool MySQLConnection::_Query(PreparedStatementBase* stmt, MySQLPreparedStatement** mysqlStmt, MySQLResult** pResult, uint64* pRowCount, uint32* pFieldCount)
283{
284 if (!m_Mysql)
285 return false;
286
287 uint32 index = stmt->GetIndex();
288
290 ASSERT(m_mStmt); // Can only be null if preparation failed, server side error or bad query
291
292 m_mStmt->BindParameters(stmt);
293 *mysqlStmt = m_mStmt;
294
295 MYSQL_STMT* msql_STMT = m_mStmt->GetSTMT();
296 MYSQL_BIND* msql_BIND = m_mStmt->GetBind();
297
298 uint32 _s = getMSTime();
299
300 if (mysql_bind_param_no_deprecated(msql_STMT, msql_BIND))
301 {
302 uint32 lErrno = mysql_errno(m_Mysql);
303 TC_LOG_ERROR("sql.sql", "SQL(p): {}\n [ERROR]: [{}] {}", m_mStmt->getQueryString(), lErrno, mysql_stmt_error(msql_STMT));
304
305 if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection)
306 return _Query(stmt, mysqlStmt, pResult, pRowCount, pFieldCount); // Try again
307
308 m_mStmt->ClearParameters();
309 return false;
310 }
311
312 if (mysql_stmt_execute(msql_STMT))
313 {
314 uint32 lErrno = mysql_errno(m_Mysql);
315 TC_LOG_ERROR("sql.sql", "SQL(p): {}\n [ERROR]: [{}] {}",
316 m_mStmt->getQueryString(), lErrno, mysql_stmt_error(msql_STMT));
317
318 if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection)
319 return _Query(stmt, mysqlStmt, pResult, pRowCount, pFieldCount); // Try again
320
321 m_mStmt->ClearParameters();
322 return false;
323 }
324
325 TC_LOG_DEBUG("sql.sql", "[{} ms] SQL(p): {}", getMSTimeDiff(_s, getMSTime()), m_mStmt->getQueryString());
326
327 m_mStmt->ClearParameters();
328
329 *pResult = reinterpret_cast<MySQLResult*>(mysql_stmt_result_metadata(msql_STMT));
330 *pRowCount = mysql_stmt_num_rows(msql_STMT);
331 *pFieldCount = mysql_stmt_field_count(msql_STMT);
332
333 return true;
334}
335
337{
338 if (!sql)
339 return nullptr;
340
341 MySQLResult* result = nullptr;
342 MySQLField* fields = nullptr;
343 uint64 rowCount = 0;
344 uint32 fieldCount = 0;
345
346 if (!_Query(sql, &result, &fields, &rowCount, &fieldCount))
347 return nullptr;
348
349 return new ResultSet(result, fields, rowCount, fieldCount);
350}
351
352bool MySQLConnection::_Query(const char* sql, MySQLResult** pResult, MySQLField** pFields, uint64* pRowCount, uint32* pFieldCount)
353{
354 if (!m_Mysql)
355 return false;
356
357 {
358 uint32 _s = getMSTime();
359
360 if (mysql_query(m_Mysql, sql))
361 {
362 uint32 lErrno = mysql_errno(m_Mysql);
363 TC_LOG_INFO("sql.sql", "SQL: {}", sql);
364 TC_LOG_ERROR("sql.sql", "[{}] {}", lErrno, mysql_error(m_Mysql));
365
366 if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection)
367 return _Query(sql, pResult, pFields, pRowCount, pFieldCount); // We try again
368
369 return false;
370 }
371 else
372 TC_LOG_DEBUG("sql.sql", "[{} ms] SQL: {}", getMSTimeDiff(_s, getMSTime()), sql);
373
374 *pResult = reinterpret_cast<MySQLResult*>(mysql_store_result(m_Mysql));
375 *pRowCount = mysql_affected_rows(m_Mysql);
376 *pFieldCount = mysql_field_count(m_Mysql);
377 }
378
379 if (!*pResult )
380 return false;
381
382 if (!*pRowCount)
383 {
384 mysql_free_result(*pResult);
385 return false;
386 }
387
388 *pFields = reinterpret_cast<MySQLField*>(mysql_fetch_fields(*pResult));
389
390 return true;
391}
392
394{
395 Execute("START TRANSACTION");
396}
397
399{
400 Execute("ROLLBACK");
401}
402
404{
405 Execute("COMMIT");
406}
407
408int MySQLConnection::ExecuteTransaction(std::shared_ptr<TransactionBase> transaction)
409{
410 std::vector<TransactionData> const& queries = transaction->m_queries;
411 if (queries.empty())
412 return -1;
413
415
416 for (auto itr = queries.begin(); itr != queries.end(); ++itr)
417 {
418 if (!std::visit([this](auto&& data) { return this->Execute(TransactionData::ToExecutable(data)); }, itr->query))
419 {
420 TC_LOG_WARN("sql.sql", "Transaction aborted. {} queries not executed.", queries.size());
421 int errorCode = GetLastError();
423 return errorCode;
424 }
425 }
426
427 // we might encounter errors during certain queries, and depending on the kind of error
428 // we might want to restart the transaction. So to prevent data loss, we only clean up when it's all done.
429 // This is done in calling functions DatabaseWorkerPool<T>::DirectCommitTransaction and TransactionTask::Execute,
430 // and not while iterating over every element.
431
433 return 0;
434}
435
436size_t MySQLConnection::EscapeString(char* to, const char* from, size_t length)
437{
438 return mysql_real_escape_string(m_Mysql, to, from, length);
439}
440
442{
443 mysql_ping(m_Mysql);
444}
445
447{
448 return mysql_errno(m_Mysql);
449}
450
452{
453 boost::asio::executor_work_guard executorWorkGuard = boost::asio::make_work_guard(context->get_executor()); // construct guard before thread starts running
454
455 m_workerThread = std::make_unique<WorkerThread>(WorkerThread{
456 .ThreadHandle = std::thread([context] { context->run(); }),
457 .WorkGuard = std::move(executorWorkGuard)
458 });
459}
460
462{
463 if (m_workerThread)
464 return m_workerThread->ThreadHandle.get_id();
465
466 return {};
467}
468
470{
471 return m_Mutex.try_lock();
472}
473
475{
476 m_Mutex.unlock();
477}
478
480{
481 return mysql_get_server_version(m_Mysql);
482}
483
485{
486 ASSERT(index < m_stmts.size(), "Tried to access invalid prepared statement index %u (max index " SZFMTD ") on database `%s`, connection type: %s",
487 index, m_stmts.size(), m_connectionInfo.database.c_str(), (m_connectionFlags & CONNECTION_ASYNC) ? "asynchronous" : "synchronous");
488 MySQLPreparedStatement* ret = m_stmts[index].get();
489 if (!ret)
490 TC_LOG_ERROR("sql.sql", "Could not fetch prepared statement {} on database `{}`, connection type: {}.",
491 index, m_connectionInfo.database, (m_connectionFlags & CONNECTION_ASYNC) ? "asynchronous" : "synchronous");
492
493 return ret;
494}
495
497{
498 // Check if specified query should be prepared on this connection
499 // i.e. don't prepare async statements on synchronous connections
500 // to save memory that will not be used.
501 if (!(m_connectionFlags & flags))
502 {
503 m_stmts[index].reset();
504 return;
505 }
506
507 MYSQL_STMT* stmt = mysql_stmt_init(m_Mysql);
508 if (!stmt)
509 {
510 TC_LOG_ERROR("sql.sql", "In mysql_stmt_init() id: {}, sql: \"{}\"", index, sql);
511 TC_LOG_ERROR("sql.sql", "{}", mysql_error(m_Mysql));
512 m_prepareError = true;
513 }
514 else
515 {
516 if (mysql_stmt_prepare(stmt, sql.data(), static_cast<unsigned long>(sql.size())))
517 {
518 TC_LOG_ERROR("sql.sql", "In mysql_stmt_prepare() id: {}, sql: \"{}\"", index, sql);
519 TC_LOG_ERROR("sql.sql", "{}", mysql_stmt_error(stmt));
520 mysql_stmt_close(stmt);
521 m_prepareError = true;
522 }
523 else
524 m_stmts[index] = std::make_unique<MySQLPreparedStatement>(reinterpret_cast<MySQLStmt*>(stmt), std::string(sql));
525 }
526}
527
529{
530 MySQLPreparedStatement* mysqlStmt = nullptr;
531 MySQLResult* result = nullptr;
532 uint64 rowCount = 0;
533 uint32 fieldCount = 0;
534
535 if (!_Query(stmt, &mysqlStmt, &result, &rowCount, &fieldCount))
536 return nullptr;
537
538 if (mysql_more_results(m_Mysql))
539 {
540 mysql_next_result(m_Mysql);
541 }
542 return new PreparedResultSet(mysqlStmt->GetSTMT(), result, rowCount, fieldCount);
543}
544
546{
547 switch (errNo)
548 {
549 case CR_SERVER_GONE_ERROR:
550 case CR_SERVER_LOST:
551 case CR_SERVER_LOST_EXTENDED:
552 {
553 if (m_Mysql)
554 {
555 TC_LOG_ERROR("sql.sql", "Lost the connection to the MySQL server!");
556
557 mysql_close(m_Mysql);
558 m_Mysql = nullptr;
559 }
560 [[fallthrough]];
561 }
562 case CR_CONN_HOST_ERROR:
563 {
564 TC_LOG_INFO("sql.sql", "Attempting to reconnect to the MySQL server...");
565
566 m_reconnecting = true;
567
568 uint32 const lErrno = Open();
569 if (!lErrno)
570 {
571 // Don't remove 'this' pointer unless you want to skip loading all prepared statements...
572 if (!this->PrepareStatements())
573 {
574 TC_LOG_FATAL("sql.sql", "Could not re-prepare statements!");
575 std::this_thread::sleep_for(std::chrono::seconds(10));
576 ABORT();
577 }
578
579 TC_LOG_INFO("sql.sql", "Successfully reconnected to {} @{}:{} ({}).",
581 (m_connectionFlags & CONNECTION_ASYNC) ? "asynchronous" : "synchronous");
582
583 m_reconnecting = false;
584 return true;
585 }
586
587 if ((--attempts) == 0)
588 {
589 // Shut down the server when the mysql server isn't
590 // reachable for some time
591 TC_LOG_FATAL("sql.sql", "Failed to reconnect to the MySQL server, "
592 "terminating the server to prevent data corruption!");
593
594 // We could also initiate a shutdown through using std::raise(SIGTERM)
595 std::this_thread::sleep_for(std::chrono::seconds(10));
596 ABORT();
597 }
598 else
599 {
600 // It's possible this attempted reconnect throws 2006 at us.
601 // To prevent crazy recursive calls, sleep here.
602 std::this_thread::sleep_for(std::chrono::seconds(3)); // Sleep 3 seconds
603 return _HandleMySQLErrno(lErrno, attempts); // Call self (recursive)
604 }
605 }
606
607 case ER_LOCK_DEADLOCK:
608 return false; // Implemented in TransactionTask::Execute and DatabaseWorkerPool<T>::DirectCommitTransaction
609 // Query related errors - skip query
610 case ER_WRONG_VALUE_COUNT:
611 case ER_DUP_ENTRY:
612 return false;
613
614 // Outdated table or database structure - terminate core
615 case ER_BAD_FIELD_ERROR:
616 case ER_NO_SUCH_TABLE:
617 TC_LOG_ERROR("sql.sql", "Your database structure is not up to date. Please make sure you've executed all queries in the sql/updates folders.");
618 std::this_thread::sleep_for(std::chrono::seconds(10));
619 ABORT();
620 return false;
621 case ER_PARSE_ERROR:
622 TC_LOG_ERROR("sql.sql", "Error while parsing SQL. Core fix required.");
623 std::this_thread::sleep_for(std::chrono::seconds(10));
624 ABORT();
625 return false;
626 default:
627 TC_LOG_ERROR("sql.sql", "Unhandled MySQL errno {}. Unexpected behaviour possible.", errNo);
628 return false;
629 }
630}
uint8_t uint8
Definition: Define.h:144
uint64_t uint64
Definition: Define.h:141
uint32_t uint32
Definition: Define.h:142
#define SZFMTD
Definition: Define.h:132
uint16 flags
Definition: DisableMgr.cpp:49
#define ABORT
Definition: Errors.h:74
#define ASSERT
Definition: Errors.h:68
#define TC_LOG_DEBUG(filterType__, message__,...)
Definition: Log.h:179
#define TC_LOG_ERROR(filterType__, message__,...)
Definition: Log.h:188
#define TC_LOG_FATAL(filterType__, message__,...)
Definition: Log.h:191
#define TC_LOG_INFO(filterType__, message__,...)
Definition: Log.h:182
#define TC_LOG_WARN(filterType__, message__,...)
Definition: Log.h:185
static auto mysql_bind_param_no_deprecated(MYSQL_STMT *stmt, MYSQL_BIND *bnd)
ConnectionFlags
@ CONNECTION_ASYNC
std::remove_pointer_t< decltype(std::declval< MYSQL_BIND >().is_null)> MySQLBool
Definition: MySQLHacks.h:32
uint32 getMSTime()
Definition: Timer.h:33
uint32 getMSTimeDiff(uint32 oldMSTime, uint32 newMSTime)
Definition: Timer.h:40
std::unique_ptr< WorkerThread > m_workerThread
Core worker thread.
std::thread::id GetWorkerThreadId() const
bool Execute(char const *sql)
void PrepareStatement(uint32 index, std::string_view sql, ConnectionFlags flags)
MySQLPreparedStatement * GetPreparedStatement(uint32 index)
int ExecuteTransaction(std::shared_ptr< TransactionBase > transaction)
MySQLConnectionInfo & m_connectionInfo
Connection info (used for logging)
PreparedStatementContainer m_stmts
PreparedStatements storage.
size_t EscapeString(char *to, const char *from, size_t length)
uint32 GetServerVersion() const
MySQLConnection(MySQLConnectionInfo &connInfo, ConnectionFlags connectionFlags)
ResultSet * Query(char const *sql)
bool _Query(char const *sql, MySQLResult **pResult, MySQLField **pFields, uint64 *pRowCount, uint32 *pFieldCount)
ConnectionFlags m_connectionFlags
Connection flags (for preparing relevant statements)
bool _HandleMySQLErrno(uint32 errNo, uint8 attempts=5)
void Unlock()
Called by parent databasepool. Will let other threads access this connection.
std::mutex m_Mutex
bool m_prepareError
Was there any error while preparing statements?
MySQLHandle * m_Mysql
MySQL Handle.
virtual ~MySQLConnection()
virtual void DoPrepareStatements()=0
void StartWorkerThread(Trinity::Asio::IoContext *context)
bool m_reconnecting
Are we reconnecting?
std::string getQueryString() const
void BindParameters(PreparedStatementBase *stmt)
Executor get_executor() noexcept
Definition: IoContext.h:47
std::size_t run()
Definition: IoContext.h:40
TC_COMMON_API std::vector< std::string_view > Tokenize(std::string_view str, char sep, bool keepEmpty)
Definition: Util.cpp:54
std::string port_or_socket
MySQLConnectionInfo(std::string const &infoString)
boost::asio::executor_work_guard< Trinity::Asio::IoContext::Executor > WorkGuard
static PreparedStatementBase * ToExecutable(std::unique_ptr< PreparedStatementBase > const &stmt)
Definition: Transaction.h:44