AzerothCore 3.3.5a
OpenSource WoW Emulator
Loading...
Searching...
No Matches
MySQLConnection Class Referenceabstract

#include "MySQLConnection.h"

Inheritance diagram for MySQLConnection:
CharacterDatabaseConnection LoginDatabaseConnection WorldDatabaseConnection

Public Member Functions

 MySQLConnection (MySQLConnectionInfo &connInfo)
 
 MySQLConnection (ProducerConsumerQueue< SQLOperation * > *queue, MySQLConnectionInfo &connInfo)
 Constructor for synchronous connections. More...
 
virtual ~MySQLConnection ()
 Constructor for asynchronous connections. More...
 
virtual uint32 Open ()
 
void Close ()
 
bool PrepareStatements ()
 
bool Execute (std::string_view sql)
 
bool Execute (PreparedStatementBase *stmt)
 
ResultSetQuery (std::string_view sql)
 
PreparedResultSetQuery (PreparedStatementBase *stmt)
 
bool _Query (std::string_view sql, MySQLResult **pResult, MySQLField **pFields, uint64 *pRowCount, uint32 *pFieldCount)
 
bool _Query (PreparedStatementBase *stmt, MySQLPreparedStatement **mysqlStmt, MySQLResult **pResult, uint64 *pRowCount, uint32 *pFieldCount)
 
void BeginTransaction ()
 
void RollbackTransaction ()
 
void CommitTransaction ()
 
int ExecuteTransaction (std::shared_ptr< TransactionBase > transaction)
 
std::size_t EscapeString (char *to, const char *from, std::size_t length)
 
void Ping ()
 
uint32 GetLastError ()
 

Protected Types

typedef std::vector< std::unique_ptr< MySQLPreparedStatement > > PreparedStatementContainer
 

Protected Member Functions

bool LockIfReady ()
 
void Unlock ()
 Called by parent databasepool. Will let other threads access this connection. More...
 
uint32 GetServerVersion () const
 
std::string GetServerInfo () const
 
MySQLPreparedStatementGetPreparedStatement (uint32 index)
 
void PrepareStatement (uint32 index, std::string_view sql, ConnectionFlags flags)
 
virtual void DoPrepareStatements ()=0
 
virtual bool _HandleMySQLErrno (uint32 errNo, char const *err="", uint8 attempts=5)
 

Protected Attributes

PreparedStatementContainer m_stmts
 
bool m_reconnecting
 PreparedStatements storage. More...
 
bool m_prepareError
 Are we reconnecting? More...
 
MySQLHandlem_Mysql
 Was there any error while preparing statements? More...
 

Private Member Functions

 MySQLConnection (MySQLConnection const &right)=delete
 
MySQLConnectionoperator= (MySQLConnection const &right)=delete
 

Private Attributes

ProducerConsumerQueue< SQLOperation * > * m_queue
 MySQL Handle. More...
 
std::unique_ptr< DatabaseWorkerm_worker
 Queue shared with other asynchronous connections. More...
 
MySQLConnectionInfom_connectionInfo
 Core worker task. More...
 
ConnectionFlags m_connectionFlags
 Connection info (used for logging) More...
 
std::mutex m_Mutex
 Connection flags (for preparing relevant statements) More...
 

Friends

template<class T >
class DatabaseWorkerPool
 
class PingOperation
 

Detailed Description

Member Typedef Documentation

◆ PreparedStatementContainer

typedef std::vector<std::unique_ptr<MySQLPreparedStatement> > MySQLConnection::PreparedStatementContainer
protected

Constructor & Destructor Documentation

◆ MySQLConnection() [1/3]

MySQLConnection::MySQLConnection ( MySQLConnectionInfo connInfo)
51 :
52 m_reconnecting(false),
53 m_prepareError(false),
54 m_Mysql(nullptr),
55 m_queue(nullptr),
56 m_connectionInfo(connInfo),
@ CONNECTION_SYNCH
Definition: MySQLConnection.h:39
ProducerConsumerQueue< SQLOperation * > * m_queue
MySQL Handle.
Definition: MySQLConnection.h:112
MySQLConnectionInfo & m_connectionInfo
Core worker task.
Definition: MySQLConnection.h:114
ConnectionFlags m_connectionFlags
Connection info (used for logging)
Definition: MySQLConnection.h:115
bool m_prepareError
Are we reconnecting?
Definition: MySQLConnection.h:108
MySQLHandle * m_Mysql
Was there any error while preparing statements?
Definition: MySQLConnection.h:109
bool m_reconnecting
PreparedStatements storage.
Definition: MySQLConnection.h:107

◆ MySQLConnection() [2/3]

MySQLConnection::MySQLConnection ( ProducerConsumerQueue< SQLOperation * > *  queue,
MySQLConnectionInfo connInfo 
)

Constructor for synchronous connections.

59 :
60 m_reconnecting(false),
61 m_prepareError(false),
62 m_Mysql(nullptr),
63 m_queue(queue),
64 m_connectionInfo(connInfo),
66{
67 m_worker = std::make_unique<DatabaseWorker>(m_queue, this);
68}
@ CONNECTION_ASYNC
Definition: MySQLConnection.h:38
std::unique_ptr< DatabaseWorker > m_worker
Queue shared with other asynchronous connections.
Definition: MySQLConnection.h:113

References m_queue, and m_worker.

◆ ~MySQLConnection()

MySQLConnection::~MySQLConnection ( )
virtual

Constructor for asynchronous connections.

71{
72 Close();
73}
void Close()
Definition: MySQLConnection.cpp:75

References Close().

◆ MySQLConnection() [3/3]

MySQLConnection::MySQLConnection ( MySQLConnection const &  right)
privatedelete

Member Function Documentation

◆ _HandleMySQLErrno()

bool MySQLConnection::_HandleMySQLErrno ( uint32  errNo,
char const *  err = "",
uint8  attempts = 5 
)
protectedvirtual
557{
558 std::string str = "";
559 switch (errNo)
560 {
561 case CR_SERVER_GONE_ERROR:
562 case CR_SERVER_LOST:
563 case CR_SERVER_LOST_EXTENDED:
564 {
565 if (m_Mysql)
566 {
567 LOG_ERROR("sql.sql", "Lost the connection to the MySQL server!");
568
569 mysql_close(m_Mysql);
570 m_Mysql = nullptr;
571 }
572 [[fallthrough]];
573 }
574 case CR_CONN_HOST_ERROR:
575 {
576 LOG_INFO("sql.sql", "Attempting to reconnect to the MySQL server...");
577
578 m_reconnecting = true;
579
580 uint32 const lErrno = Open();
581 if (!lErrno)
582 {
583 // Don't remove 'this' pointer unless you want to skip loading all prepared statements...
584 if (!this->PrepareStatements())
585 {
586 str = "Could not re-prepare statements!";
587 LOG_FATAL("sql.sql", "{}", str);
588 std::this_thread::sleep_for(10s);
589 ABORT("{}\n\n[{}] {}", str, errNo, err);
590 }
591
592 LOG_INFO("sql.sql", "Successfully reconnected to {} @{}:{} ({}).",
594 (m_connectionFlags & CONNECTION_ASYNC) ? "asynchronous" : "synchronous");
595
596 m_reconnecting = false;
597 return true;
598 }
599
600 if ((--attempts) == 0)
601 {
602 // Shut down the server when the mysql server isn't
603 // reachable for some time
604 str = "Failed to reconnect to the MySQL server, terminating the server to prevent data corruption!";
605 LOG_FATAL("sql.sql", "{}", str);
606
607 // We could also initiate a shutdown through using std::raise(SIGTERM)
608 std::this_thread::sleep_for(10s);
609 ABORT("{}\n\n[{}] {}", str, errNo, err);
610 }
611 else
612 {
613 // It's possible this attempted reconnect throws 2006 at us.
614 // To prevent crazy recursive calls, sleep here.
615 std::this_thread::sleep_for(3s); // Sleep 3 seconds
616 return _HandleMySQLErrno(lErrno, mysql_error(m_Mysql), attempts); // Call self (recursive)
617 }
618 [[fallthrough]];
619 }
620
621 case ER_LOCK_DEADLOCK:
622 return false; // Implemented in TransactionTask::Execute and DatabaseWorkerPool<T>::DirectCommitTransaction
623
624 // Query related errors - skip query
625 case ER_WRONG_VALUE_COUNT:
626 case ER_DUP_ENTRY:
627 return false;
628
629 // Outdated table or database structure - terminate core
630 case ER_BAD_FIELD_ERROR:
631 case ER_NO_SUCH_TABLE:
632 str = "Your database structure is not up to date. Please make sure you've executed all queries in the sql/updates folders.";
633 LOG_FATAL("sql.sql", "{}", str);
634 std::this_thread::sleep_for(10s);
635 ABORT("{}\n\n[{}] {}", str, errNo, err);
636 return false;
637 case ER_PARSE_ERROR:
638 str = "Error while parsing SQL. Core fix required.";
639 LOG_FATAL("sql.sql", "{}", str);
640 std::this_thread::sleep_for(10s);
641 ABORT("{}\n\n[{}] {}", str, errNo, err);
642 return false;
643 default:
644 LOG_ERROR("sql.sql", "Unhandled MySQL errno {}. Unexpected behaviour possible.", errNo);
645 return false;
646 }
647}
#define LOG_FATAL(filterType__,...)
Definition: Log.h:152
#define LOG_INFO(filterType__,...)
Definition: Log.h:164
#define LOG_ERROR(filterType__,...)
Definition: Log.h:156
std::uint32_t uint32
Definition: Define.h:107
#define ABORT
Definition: Errors.h:76
std::string host
Definition: MySQLConnection.h:50
std::string port_or_socket
Definition: MySQLConnection.h:51
std::string database
Definition: MySQLConnection.h:49
virtual bool _HandleMySQLErrno(uint32 errNo, char const *err="", uint8 attempts=5)
Definition: MySQLConnection.cpp:556
virtual uint32 Open()
Definition: MySQLConnection.cpp:88
bool PrepareStatements()
Definition: MySQLConnection.cpp:170

References _HandleMySQLErrno(), ABORT, CONNECTION_ASYNC, MySQLConnectionInfo::database, MySQLConnectionInfo::host, LOG_ERROR, LOG_FATAL, LOG_INFO, m_connectionFlags, m_connectionInfo, m_Mysql, m_reconnecting, Open(), MySQLConnectionInfo::port_or_socket, and PrepareStatements().

Referenced by _HandleMySQLErrno(), _Query(), and Execute().

◆ _Query() [1/2]

bool MySQLConnection::_Query ( PreparedStatementBase stmt,
MySQLPreparedStatement **  mysqlStmt,
MySQLResult **  pResult,
uint64 pRowCount,
uint32 pFieldCount 
)
255{
256 if (!m_Mysql)
257 return false;
258
259 uint32 index = stmt->GetIndex();
260
262 ASSERT(m_mStmt); // Can only be null if preparation failed, server side error or bad query
263
264 m_mStmt->BindParameters(stmt);
265 *mysqlStmt = m_mStmt;
266
267 MYSQL_STMT* msql_STMT = m_mStmt->GetSTMT();
268 MYSQL_BIND* msql_BIND = m_mStmt->GetBind();
269
270 uint32 _s = getMSTime();
271
272#if MYSQL_VERSION_ID >= 80300
273 if (mysql_stmt_bind_named_param(msql_STMT, msql_BIND, m_mStmt->GetParameterCount(), nullptr))
274#else
275 if (mysql_stmt_bind_param(msql_STMT, msql_BIND))
276#endif
277 {
278 uint32 lErrno = mysql_errno(m_Mysql);
279 LOG_ERROR("sql.sql", "SQL(p): {}\n [ERROR]: [{}] {}", m_mStmt->getQueryString(), lErrno, mysql_stmt_error(msql_STMT));
280
281 if (_HandleMySQLErrno(lErrno, mysql_stmt_error(msql_STMT))) // If it returns true, an error was handled successfully (i.e. reconnection)
282 return _Query(stmt, mysqlStmt, pResult, pRowCount, pFieldCount); // Try again
283
284 m_mStmt->ClearParameters();
285 return false;
286 }
287
288 if (mysql_stmt_execute(msql_STMT))
289 {
290 uint32 lErrno = mysql_errno(m_Mysql);
291 LOG_ERROR("sql.sql", "SQL(p): {}\n [ERROR]: [{}] {}", m_mStmt->getQueryString(), lErrno, mysql_stmt_error(msql_STMT));
292
293 if (_HandleMySQLErrno(lErrno, mysql_stmt_error(msql_STMT))) // If it returns true, an error was handled successfully (i.e. reconnection)
294 return _Query(stmt, mysqlStmt, pResult, pRowCount, pFieldCount); // Try again
295
296 m_mStmt->ClearParameters();
297 return false;
298 }
299
300 LOG_DEBUG("sql.sql", "[{} ms] SQL(p): {}", getMSTimeDiff(_s, getMSTime()), m_mStmt->getQueryString());
301
302 m_mStmt->ClearParameters();
303
304 *pResult = reinterpret_cast<MySQLResult*>(mysql_stmt_result_metadata(msql_STMT));
305 *pRowCount = mysql_stmt_affected_rows(msql_STMT);
306 *pFieldCount = mysql_stmt_field_count(msql_STMT);
307
308 return true;
309}
#define LOG_DEBUG(filterType__,...)
Definition: Log.h:168
uint32 getMSTime()
Definition: Timer.h:103
uint32 getMSTimeDiff(uint32 oldMSTime, uint32 newMSTime)
Definition: Timer.h:110
#define ASSERT
Definition: Errors.h:68
MySQLPreparedStatement * GetPreparedStatement(uint32 index)
Definition: MySQLConnection.cpp:492
bool _Query(std::string_view sql, MySQLResult **pResult, MySQLField **pFields, uint64 *pRowCount, uint32 *pFieldCount)
Definition: MySQLConnection.cpp:327
Definition: MySQLHacks.h:25
Definition: MySQLPreparedStatement.h:34
uint32 GetParameterCount() const
Definition: MySQLPreparedStatement.h:44
std::string getQueryString() const
Definition: MySQLPreparedStatement.cpp:189
void ClearParameters()
Definition: MySQLPreparedStatement.cpp:89
MySQLStmt * GetSTMT()
Definition: MySQLPreparedStatement.h:55
void BindParameters(PreparedStatementBase *stmt)
Definition: MySQLPreparedStatement.cpp:68
MySQLBind * GetBind()
Definition: MySQLPreparedStatement.h:56
uint32 GetIndex() const
Definition: PreparedStatement.h:124

References _HandleMySQLErrno(), _Query(), ASSERT, MySQLPreparedStatement::BindParameters(), MySQLPreparedStatement::ClearParameters(), MySQLPreparedStatement::GetBind(), PreparedStatementBase::GetIndex(), getMSTime(), getMSTimeDiff(), MySQLPreparedStatement::GetParameterCount(), GetPreparedStatement(), MySQLPreparedStatement::getQueryString(), MySQLPreparedStatement::GetSTMT(), LOG_DEBUG, LOG_ERROR, and m_Mysql.

◆ _Query() [2/2]

bool MySQLConnection::_Query ( std::string_view  sql,
MySQLResult **  pResult,
MySQLField **  pFields,
uint64 pRowCount,
uint32 pFieldCount 
)
328{
329 if (!m_Mysql)
330 return false;
331
332 {
333 uint32 _s = getMSTime();
334
335 if (mysql_query(m_Mysql, std::string(sql).c_str()))
336 {
337 uint32 lErrno = mysql_errno(m_Mysql);
338 LOG_INFO("sql.sql", "SQL: {}", sql);
339 LOG_ERROR("sql.sql", "[{}] {}", lErrno, mysql_error(m_Mysql));
340
341 if (_HandleMySQLErrno(lErrno, mysql_error(m_Mysql))) // If it returns true, an error was handled successfully (i.e. reconnection)
342 return _Query(sql, pResult, pFields, pRowCount, pFieldCount); // We try again
343
344 return false;
345 }
346 else
347 LOG_DEBUG("sql.sql", "[{} ms] SQL: {}", getMSTimeDiff(_s, getMSTime()), sql);
348
349 *pResult = reinterpret_cast<MySQLResult*>(mysql_store_result(m_Mysql));
350 *pRowCount = mysql_affected_rows(m_Mysql);
351 *pFieldCount = mysql_field_count(m_Mysql);
352 }
353
354 if (!*pResult)
355 return false;
356
357 if (!*pRowCount)
358 {
359 mysql_free_result(*pResult);
360 return false;
361 }
362
363 *pFields = reinterpret_cast<MySQLField*>(mysql_fetch_fields(*pResult));
364
365 return true;
366}
Definition: MySQLHacks.h:26

References _HandleMySQLErrno(), _Query(), getMSTime(), getMSTimeDiff(), LOG_DEBUG, LOG_ERROR, LOG_INFO, and m_Mysql.

Referenced by _Query(), and Query().

◆ BeginTransaction()

void MySQLConnection::BeginTransaction ( )
369{
370 Execute("START TRANSACTION");
371}
bool Execute(std::string_view sql)
Definition: MySQLConnection.cpp:176

References Execute().

Referenced by ExecuteTransaction().

◆ Close()

void MySQLConnection::Close ( )
76{
77 // Stop the worker thread before the statements are cleared
78 m_worker.reset();
79 m_stmts.clear();
80
81 if (m_Mysql)
82 {
83 mysql_close(m_Mysql);
84 m_Mysql = nullptr;
85 }
86}
PreparedStatementContainer m_stmts
Definition: MySQLConnection.h:106

References m_Mysql, m_stmts, and m_worker.

Referenced by ~MySQLConnection().

◆ CommitTransaction()

void MySQLConnection::CommitTransaction ( )
379{
380 Execute("COMMIT");
381}

References Execute().

Referenced by ExecuteTransaction().

◆ DoPrepareStatements()

virtual void MySQLConnection::DoPrepareStatements ( )
protectedpure virtual

◆ EscapeString()

std::size_t MySQLConnection::EscapeString ( char *  to,
const char *  from,
std::size_t  length 
)
458{
459 return mysql_real_escape_string(m_Mysql, to, from, length);
460}

References m_Mysql.

◆ Execute() [1/2]

bool MySQLConnection::Execute ( PreparedStatementBase stmt)
204{
205 if (!m_Mysql)
206 return false;
207
208 uint32 index = stmt->GetIndex();
209
211 ASSERT(m_mStmt); // Can only be null if preparation failed, server side error or bad query
212
213 m_mStmt->BindParameters(stmt);
214
215 MYSQL_STMT* msql_STMT = m_mStmt->GetSTMT();
216 MYSQL_BIND* msql_BIND = m_mStmt->GetBind();
217
218 uint32 _s = getMSTime();
219
220#if MYSQL_VERSION_ID >= 80300
221 if (mysql_stmt_bind_named_param(msql_STMT, msql_BIND, m_mStmt->GetParameterCount(), nullptr))
222#else
223 if (mysql_stmt_bind_param(msql_STMT, msql_BIND))
224#endif
225 {
226 uint32 lErrno = mysql_errno(m_Mysql);
227 LOG_ERROR("sql.sql", "SQL(p): {}\n [ERROR]: [{}] {}", m_mStmt->getQueryString(), lErrno, mysql_stmt_error(msql_STMT));
228
229 if (_HandleMySQLErrno(lErrno, mysql_stmt_error(msql_STMT))) // If it returns true, an error was handled successfully (i.e. reconnection)
230 return Execute(stmt); // Try again
231
232 m_mStmt->ClearParameters();
233 return false;
234 }
235
236 if (mysql_stmt_execute(msql_STMT))
237 {
238 uint32 lErrno = mysql_errno(m_Mysql);
239 LOG_ERROR("sql.sql", "SQL(p): {}\n [ERROR]: [{}] {}", m_mStmt->getQueryString(), lErrno, mysql_stmt_error(msql_STMT));
240
241 if (_HandleMySQLErrno(lErrno, mysql_stmt_error(msql_STMT))) // If it returns true, an error was handled successfully (i.e. reconnection)
242 return Execute(stmt); // Try again
243
244 m_mStmt->ClearParameters();
245 return false;
246 }
247
248 LOG_DEBUG("sql.sql", "[{} ms] SQL(p): {}", getMSTimeDiff(_s, getMSTime()), m_mStmt->getQueryString());
249
250 m_mStmt->ClearParameters();
251 return true;
252}

References _HandleMySQLErrno(), ASSERT, MySQLPreparedStatement::BindParameters(), MySQLPreparedStatement::ClearParameters(), Execute(), MySQLPreparedStatement::GetBind(), PreparedStatementBase::GetIndex(), getMSTime(), getMSTimeDiff(), MySQLPreparedStatement::GetParameterCount(), GetPreparedStatement(), MySQLPreparedStatement::getQueryString(), MySQLPreparedStatement::GetSTMT(), LOG_DEBUG, LOG_ERROR, and m_Mysql.

◆ Execute() [2/2]

bool MySQLConnection::Execute ( std::string_view  sql)
177{
178 if (!m_Mysql)
179 return false;
180
181 {
182 uint32 _s = getMSTime();
183
184 if (mysql_query(m_Mysql, std::string(sql).c_str()))
185 {
186 uint32 lErrno = mysql_errno(m_Mysql);
187
188 LOG_INFO("sql.sql", "SQL: {}", sql);
189 LOG_ERROR("sql.sql", "[{}] {}", lErrno, mysql_error(m_Mysql));
190
191 if (_HandleMySQLErrno(lErrno, mysql_error(m_Mysql))) // If it returns true, an error was handled successfully (i.e. reconnection)
192 return Execute(sql); // Try again
193
194 return false;
195 }
196 else
197 LOG_DEBUG("sql.sql", "[{} ms] SQL: {}", getMSTimeDiff(_s, getMSTime()), sql);
198 }
199
200 return true;
201}

References _HandleMySQLErrno(), Execute(), getMSTime(), getMSTimeDiff(), LOG_DEBUG, LOG_ERROR, LOG_INFO, and m_Mysql.

Referenced by BeginTransaction(), CommitTransaction(), BasicStatementTask::Execute(), PreparedStatementTask::Execute(), Execute(), ExecuteTransaction(), and RollbackTransaction().

◆ ExecuteTransaction()

int MySQLConnection::ExecuteTransaction ( std::shared_ptr< TransactionBase transaction)
384{
385 std::vector<SQLElementData> const& queries = transaction->m_queries;
386 if (queries.empty())
387 return -1;
388
390
391 for (auto const& data : queries)
392 {
393 switch (data.type)
394 {
396 {
397 PreparedStatementBase* stmt = nullptr;
398
399 try
400 {
401 stmt = std::get<PreparedStatementBase*>(data.element);
402 }
403 catch (const std::bad_variant_access& ex)
404 {
405 LOG_FATAL("sql.sql", "> PreparedStatementBase not found in SQLElementData. {}", ex.what());
406 ABORT();
407 }
408
409 ASSERT(stmt);
410
411 if (!Execute(stmt))
412 {
413 LOG_WARN("sql.sql", "Transaction aborted. {} queries not executed.", queries.size());
414 int errorCode = GetLastError();
416 return errorCode;
417 }
418 }
419 break;
420 case SQL_ELEMENT_RAW:
421 {
422 std::string sql{};
423
424 try
425 {
426 sql = std::get<std::string>(data.element);
427 }
428 catch (const std::bad_variant_access& ex)
429 {
430 LOG_FATAL("sql.sql", "> std::string not found in SQLElementData. {}", ex.what());
431 ABORT();
432 }
433
434 ASSERT(!sql.empty());
435
436 if (!Execute(sql))
437 {
438 LOG_WARN("sql.sql", "Transaction aborted. {} queries not executed.", queries.size());
439 uint32 errorCode = GetLastError();
441 return errorCode;
442 }
443 }
444 break;
445 }
446 }
447
448 // we might encounter errors during certain queries, and depending on the kind of error
449 // we might want to restart the transaction. So to prevent data loss, we only clean up when it's all done.
450 // This is done in calling functions DatabaseWorkerPool<T>::DirectCommitTransaction and TransactionTask::Execute,
451 // and not while iterating over every element.
452
454 return 0;
455}
#define LOG_WARN(filterType__,...)
Definition: Log.h:160
@ SQL_ELEMENT_RAW
Definition: SQLOperation.h:28
@ SQL_ELEMENT_PREPARED
Definition: SQLOperation.h:29
void CommitTransaction()
Definition: MySQLConnection.cpp:378
void RollbackTransaction()
Definition: MySQLConnection.cpp:373
void BeginTransaction()
Definition: MySQLConnection.cpp:368
uint32 GetLastError()
Definition: MySQLConnection.cpp:467
Definition: PreparedStatement.h:69

References ABORT, ASSERT, BeginTransaction(), CommitTransaction(), Execute(), GetLastError(), LOG_FATAL, LOG_WARN, RollbackTransaction(), SQL_ELEMENT_PREPARED, and SQL_ELEMENT_RAW.

Referenced by TransactionTask::TryExecute().

◆ GetLastError()

uint32 MySQLConnection::GetLastError ( )
468{
469 return mysql_errno(m_Mysql);
470}

References m_Mysql.

Referenced by ExecuteTransaction().

◆ GetPreparedStatement()

MySQLPreparedStatement * MySQLConnection::GetPreparedStatement ( uint32  index)
protected
493{
494 ASSERT(index < m_stmts.size(), "Tried to access invalid prepared statement index {} (max index {}) on database `{}`, connection type: {}",
495 index, m_stmts.size(), m_connectionInfo.database, (m_connectionFlags & CONNECTION_ASYNC) ? "asynchronous" : "synchronous");
496
497 MySQLPreparedStatement* ret = m_stmts[index].get();
498
499 if (!ret)
500 LOG_ERROR("sql.sql", "Could not fetch prepared statement {} on database `{}`, connection type: {}.",
501 index, m_connectionInfo.database, (m_connectionFlags & CONNECTION_ASYNC) ? "asynchronous" : "synchronous");
502
503 return ret;
504}

References ASSERT, CONNECTION_ASYNC, MySQLConnectionInfo::database, LOG_ERROR, m_connectionFlags, m_connectionInfo, and m_stmts.

Referenced by _Query(), and Execute().

◆ GetServerInfo()

std::string MySQLConnection::GetServerInfo ( ) const
protected
488{
489 return mysql_get_server_info(m_Mysql);
490}

References m_Mysql.

◆ GetServerVersion()

uint32 MySQLConnection::GetServerVersion ( ) const
protected
483{
484 return mysql_get_server_version(m_Mysql);
485}

References m_Mysql.

◆ LockIfReady()

bool MySQLConnection::LockIfReady ( )
protected

Tries to acquire lock. If lock is acquired by another thread the calling parent will just try another connection

473{
474 return m_Mutex.try_lock();
475}
std::mutex m_Mutex
Connection flags (for preparing relevant statements)
Definition: MySQLConnection.h:116

References m_Mutex.

◆ Open()

uint32 MySQLConnection::Open ( )
virtual
89{
90 MYSQL* mysqlInit = mysql_init(nullptr);
91 if (!mysqlInit)
92 {
93 LOG_ERROR("sql.driver", "Could not initialize Mysql connection to database `{}`", m_connectionInfo.database);
94 return CR_UNKNOWN_ERROR;
95 }
96
97 uint32 port;
98 char const* unix_socket;
99
100 mysql_options(mysqlInit, MYSQL_SET_CHARSET_NAME, "utf8");
101
102#ifdef _WIN32
103 if (m_connectionInfo.host == ".") // named pipe use option (Windows)
104 {
105 unsigned int opt = MYSQL_PROTOCOL_PIPE;
106 mysql_options(mysqlInit, MYSQL_OPT_PROTOCOL, (char const*)&opt);
107 port = 0;
108 unix_socket = 0;
109 }
110 else // generic case
111 {
112 port = *Acore::StringTo<uint32>(m_connectionInfo.port_or_socket);
113 unix_socket = 0;
114 }
115#else
116 if (m_connectionInfo.host == ".") // socket use option (Unix/Linux)
117 {
118 unsigned int opt = MYSQL_PROTOCOL_SOCKET;
119 mysql_options(mysqlInit, MYSQL_OPT_PROTOCOL, (char const*)&opt);
120 m_connectionInfo.host = "localhost";
121 port = 0;
122 unix_socket = m_connectionInfo.port_or_socket.c_str();
123 }
124 else // generic case
125 {
126 port = *Acore::StringTo<uint32>(m_connectionInfo.port_or_socket);
127 unix_socket = nullptr;
128 }
129#endif
130
131 if (m_connectionInfo.ssl != "")
132 {
133 mysql_ssl_mode opt_use_ssl = SSL_MODE_DISABLED;
134 if (m_connectionInfo.ssl == "ssl")
135 {
136 opt_use_ssl = SSL_MODE_REQUIRED;
137 }
138
139 mysql_options(mysqlInit, MYSQL_OPT_SSL_MODE, (char const*)&opt_use_ssl);
140 }
141
142 m_Mysql = reinterpret_cast<MySQLHandle*>(mysql_real_connect(mysqlInit, m_connectionInfo.host.c_str(), m_connectionInfo.user.c_str(),
143 m_connectionInfo.password.c_str(), m_connectionInfo.database.c_str(), port, unix_socket, 0));
144
145 if (m_Mysql)
146 {
147 if (!m_reconnecting)
148 {
149 LOG_INFO("sql.sql", "MySQL client library: {}", mysql_get_client_info());
150 LOG_INFO("sql.sql", "MySQL server ver: {} ", mysql_get_server_info(m_Mysql));
151 }
152
153 LOG_INFO("sql.sql", "Connected to MySQL database at {}", m_connectionInfo.host);
154 mysql_autocommit(m_Mysql, 1);
155
156 // set connection properties to UTF8 to properly handle locales for different
157 // server configs - core sends data in UTF8, so MySQL must expect UTF8 too
158 mysql_set_character_set(m_Mysql, "utf8mb4");
159 return 0;
160 }
161 else
162 {
163 LOG_ERROR("sql.driver", "Could not connect to MySQL database at {}: {}", m_connectionInfo.host, mysql_error(mysqlInit));
164 uint32 errorCode = mysql_errno(mysqlInit);
165 mysql_close(mysqlInit);
166 return errorCode;
167 }
168}
std::string user
Definition: MySQLConnection.h:47
std::string ssl
Definition: MySQLConnection.h:52
std::string password
Definition: MySQLConnection.h:48
Definition: MySQLHacks.h:24

References MySQLConnectionInfo::database, MySQLConnectionInfo::host, LOG_ERROR, LOG_INFO, m_connectionInfo, m_Mysql, m_reconnecting, MySQLConnectionInfo::password, MySQLConnectionInfo::port_or_socket, MySQLConnectionInfo::ssl, and MySQLConnectionInfo::user.

Referenced by _HandleMySQLErrno().

◆ operator=()

MySQLConnection & MySQLConnection::operator= ( MySQLConnection const &  right)
privatedelete

◆ Ping()

void MySQLConnection::Ping ( )
463{
464 mysql_ping(m_Mysql);
465}

References m_Mysql.

Referenced by PingOperation::Execute().

◆ PrepareStatement()

void MySQLConnection::PrepareStatement ( uint32  index,
std::string_view  sql,
ConnectionFlags  flags 
)
protected
507{
508 // Check if specified query should be prepared on this connection
509 // i.e. don't prepare async statements on synchronous connections
510 // to save memory that will not be used.
511 if (!(m_connectionFlags & flags))
512 {
513 m_stmts[index].reset();
514 return;
515 }
516
517 MYSQL_STMT* stmt = mysql_stmt_init(m_Mysql);
518 if (!stmt)
519 {
520 LOG_ERROR("sql.sql", "In mysql_stmt_init() id: {}, sql: \"{}\"", index, sql);
521 LOG_ERROR("sql.sql", "{}", mysql_error(m_Mysql));
522 m_prepareError = true;
523 }
524 else
525 {
526 if (mysql_stmt_prepare(stmt, std::string(sql).c_str(), static_cast<unsigned long>(sql.size())))
527 {
528 LOG_ERROR("sql.sql", "In mysql_stmt_prepare() id: {}, sql: \"{}\"", index, sql);
529 LOG_ERROR("sql.sql", "{}", mysql_stmt_error(stmt));
530 mysql_stmt_close(stmt);
531 m_prepareError = true;
532 }
533 else
534 m_stmts[index] = std::make_unique<MySQLPreparedStatement>(reinterpret_cast<MySQLStmt*>(stmt), sql);
535 }
536}
Definition: MySQLHacks.h:28

References LOG_ERROR, m_connectionFlags, m_Mysql, m_prepareError, and m_stmts.

Referenced by CharacterDatabaseConnection::DoPrepareStatements(), LoginDatabaseConnection::DoPrepareStatements(), and WorldDatabaseConnection::DoPrepareStatements().

◆ PrepareStatements()

bool MySQLConnection::PrepareStatements ( )
171{
173 return !m_prepareError;
174}
virtual void DoPrepareStatements()=0

References DoPrepareStatements(), and m_prepareError.

Referenced by _HandleMySQLErrno().

◆ Query() [1/2]

PreparedResultSet * MySQLConnection::Query ( PreparedStatementBase stmt)
539{
540 MySQLPreparedStatement* mysqlStmt = nullptr;
541 MySQLResult* result = nullptr;
542 uint64 rowCount = 0;
543 uint32 fieldCount = 0;
544
545 if (!_Query(stmt, &mysqlStmt, &result, &rowCount, &fieldCount))
546 return nullptr;
547
548 if (mysql_more_results(m_Mysql))
549 {
550 mysql_next_result(m_Mysql);
551 }
552
553 return new PreparedResultSet(mysqlStmt->GetSTMT(), result, rowCount, fieldCount);
554}
std::uint64_t uint64
Definition: Define.h:106
Definition: QueryResult.h:99

References _Query(), MySQLPreparedStatement::GetSTMT(), and m_Mysql.

◆ Query() [2/2]

ResultSet * MySQLConnection::Query ( std::string_view  sql)
312{
313 if (sql.empty())
314 return nullptr;
315
316 MySQLResult* result = nullptr;
317 MySQLField* fields = nullptr;
318 uint64 rowCount = 0;
319 uint32 fieldCount = 0;
320
321 if (!_Query(sql, &result, &fields, &rowCount, &fieldCount))
322 return nullptr;
323
324 return new ResultSet(result, fields, rowCount, fieldCount);
325}
Definition: QueryResult.h:49

References _Query().

Referenced by BasicStatementTask::Execute(), PreparedStatementTask::Execute(), and SQLQueryHolderTask::Execute().

◆ RollbackTransaction()

void MySQLConnection::RollbackTransaction ( )
374{
375 Execute("ROLLBACK");
376}

References Execute().

Referenced by ExecuteTransaction().

◆ Unlock()

void MySQLConnection::Unlock ( )
protected

Called by parent databasepool. Will let other threads access this connection.

478{
479 m_Mutex.unlock();
480}

References m_Mutex.

Friends And Related Function Documentation

◆ DatabaseWorkerPool

template<class T >
friend class DatabaseWorkerPool
friend

◆ PingOperation

friend class PingOperation
friend

Member Data Documentation

◆ m_connectionFlags

ConnectionFlags MySQLConnection::m_connectionFlags
private

Connection info (used for logging)

Referenced by _HandleMySQLErrno(), GetPreparedStatement(), and PrepareStatement().

◆ m_connectionInfo

MySQLConnectionInfo& MySQLConnection::m_connectionInfo
private

Core worker task.

Referenced by _HandleMySQLErrno(), GetPreparedStatement(), and Open().

◆ m_Mutex

std::mutex MySQLConnection::m_Mutex
private

Connection flags (for preparing relevant statements)

Referenced by LockIfReady(), and Unlock().

◆ m_Mysql

MySQLHandle* MySQLConnection::m_Mysql
protected

◆ m_prepareError

bool MySQLConnection::m_prepareError
protected

Are we reconnecting?

Referenced by PrepareStatement(), and PrepareStatements().

◆ m_queue

ProducerConsumerQueue<SQLOperation*>* MySQLConnection::m_queue
private

MySQL Handle.

Referenced by MySQLConnection().

◆ m_reconnecting

◆ m_stmts

◆ m_worker

std::unique_ptr<DatabaseWorker> MySQLConnection::m_worker
private

Queue shared with other asynchronous connections.

Referenced by Close(), and MySQLConnection().