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)
50 :
51 m_reconnecting(false),
52 m_prepareError(false),
53 m_Mysql(nullptr),
54 m_queue(nullptr),
55 m_connectionInfo(connInfo),
@ CONNECTION_SYNCH
Definition: MySQLConnection.h:38
ProducerConsumerQueue< SQLOperation * > * m_queue
MySQL Handle.
Definition: MySQLConnection.h:111
MySQLConnectionInfo & m_connectionInfo
Core worker task.
Definition: MySQLConnection.h:113
ConnectionFlags m_connectionFlags
Connection info (used for logging)
Definition: MySQLConnection.h:114
bool m_prepareError
Are we reconnecting?
Definition: MySQLConnection.h:107
MySQLHandle * m_Mysql
Was there any error while preparing statements?
Definition: MySQLConnection.h:108
bool m_reconnecting
PreparedStatements storage.
Definition: MySQLConnection.h:106

◆ MySQLConnection() [2/3]

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

Constructor for synchronous connections.

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

References m_queue, and m_worker.

◆ ~MySQLConnection()

MySQLConnection::~MySQLConnection ( )
virtual

Constructor for asynchronous connections.

70{
71 Close();
72}
void Close()
Definition: MySQLConnection.cpp:74

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

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 
)
254{
255 if (!m_Mysql)
256 return false;
257
258 uint32 index = stmt->GetIndex();
259
261 ASSERT(m_mStmt); // Can only be null if preparation failed, server side error or bad query
262
263 m_mStmt->BindParameters(stmt);
264 *mysqlStmt = m_mStmt;
265
266 MYSQL_STMT* msql_STMT = m_mStmt->GetSTMT();
267 MYSQL_BIND* msql_BIND = m_mStmt->GetBind();
268
269 uint32 _s = getMSTime();
270
271#if MYSQL_VERSION_ID >= 80300
272 if (mysql_stmt_bind_named_param(msql_STMT, msql_BIND, m_mStmt->GetParameterCount(), nullptr))
273#else
274 if (mysql_stmt_bind_param(msql_STMT, msql_BIND))
275#endif
276 {
277 uint32 lErrno = mysql_errno(m_Mysql);
278 LOG_ERROR("sql.sql", "SQL(p): {}\n [ERROR]: [{}] {}", m_mStmt->getQueryString(), lErrno, mysql_stmt_error(msql_STMT));
279
280 if (_HandleMySQLErrno(lErrno, mysql_stmt_error(msql_STMT))) // If it returns true, an error was handled successfully (i.e. reconnection)
281 return _Query(stmt, mysqlStmt, pResult, pRowCount, pFieldCount); // Try again
282
283 m_mStmt->ClearParameters();
284 return false;
285 }
286
287 if (mysql_stmt_execute(msql_STMT))
288 {
289 uint32 lErrno = mysql_errno(m_Mysql);
290 LOG_ERROR("sql.sql", "SQL(p): {}\n [ERROR]: [{}] {}", m_mStmt->getQueryString(), lErrno, mysql_stmt_error(msql_STMT));
291
292 if (_HandleMySQLErrno(lErrno, mysql_stmt_error(msql_STMT))) // If it returns true, an error was handled successfully (i.e. reconnection)
293 return _Query(stmt, mysqlStmt, pResult, pRowCount, pFieldCount); // Try again
294
295 m_mStmt->ClearParameters();
296 return false;
297 }
298
299 LOG_DEBUG("sql.sql", "[{} ms] SQL(p): {}", getMSTimeDiff(_s, getMSTime()), m_mStmt->getQueryString());
300
301 m_mStmt->ClearParameters();
302
303 *pResult = reinterpret_cast<MySQLResult*>(mysql_stmt_result_metadata(msql_STMT));
304 *pRowCount = mysql_stmt_affected_rows(msql_STMT);
305 *pFieldCount = mysql_stmt_field_count(msql_STMT);
306
307 return true;
308}
#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:491
bool _Query(std::string_view sql, MySQLResult **pResult, MySQLField **pFields, uint64 *pRowCount, uint32 *pFieldCount)
Definition: MySQLConnection.cpp:326
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:123

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

References Execute().

Referenced by ExecuteTransaction().

◆ Close()

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

References m_Mysql, m_stmts, and m_worker.

Referenced by ~MySQLConnection().

◆ CommitTransaction()

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

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 
)
457{
458 return mysql_real_escape_string(m_Mysql, to, from, length);
459}

References m_Mysql.

◆ Execute() [1/2]

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

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

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

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 ( )
467{
468 return mysql_errno(m_Mysql);
469}

References m_Mysql.

Referenced by ExecuteTransaction().

◆ GetPreparedStatement()

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

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
487{
488 return mysql_get_server_info(m_Mysql);
489}

References m_Mysql.

◆ GetServerVersion()

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

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

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

References m_Mutex.

◆ Open()

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

References m_Mysql.

Referenced by PingOperation::Execute().

◆ PrepareStatement()

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

References DoPrepareStatements(), and m_prepareError.

Referenced by _HandleMySQLErrno().

◆ Query() [1/2]

PreparedResultSet * MySQLConnection::Query ( PreparedStatementBase stmt)
538{
539 MySQLPreparedStatement* mysqlStmt = nullptr;
540 MySQLResult* result = nullptr;
541 uint64 rowCount = 0;
542 uint32 fieldCount = 0;
543
544 if (!_Query(stmt, &mysqlStmt, &result, &rowCount, &fieldCount))
545 return nullptr;
546
547 if (mysql_more_results(m_Mysql))
548 {
549 mysql_next_result(m_Mysql);
550 }
551
552 return new PreparedResultSet(mysqlStmt->GetSTMT(), result, rowCount, fieldCount);
553}
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)
311{
312 if (sql.empty())
313 return nullptr;
314
315 MySQLResult* result = nullptr;
316 MySQLField* fields = nullptr;
317 uint64 rowCount = 0;
318 uint32 fieldCount = 0;
319
320 if (!_Query(sql, &result, &fields, &rowCount, &fieldCount))
321 return nullptr;
322
323 return new ResultSet(result, fields, rowCount, fieldCount);
324}
Definition: QueryResult.h:49

References _Query().

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

◆ RollbackTransaction()

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

References Execute().

Referenced by ExecuteTransaction().

◆ Unlock()

void MySQLConnection::Unlock ( )
protected

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

477{
478 m_Mutex.unlock();
479}

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().