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

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 
)
265{
266 if (!m_Mysql)
267 return false;
268
269 uint32 index = stmt->GetIndex();
270
272 ASSERT(m_mStmt); // Can only be null if preparation failed, server side error or bad query
273
274 m_mStmt->BindParameters(stmt);
275 *mysqlStmt = m_mStmt;
276
277 MYSQL_STMT* msql_STMT = m_mStmt->GetSTMT();
278 MYSQL_BIND* msql_BIND = m_mStmt->GetBind();
279
280 uint32 _s = getMSTime();
281
282#if !defined(MARIADB_VERSION_ID) && (MYSQL_VERSION_ID >= 80300)
283 if (mysql_stmt_bind_named_param(msql_STMT, msql_BIND, m_mStmt->GetParameterCount(), nullptr))
284#else
285 if (mysql_stmt_bind_param(msql_STMT, msql_BIND))
286#endif
287 {
288 uint32 lErrno = mysql_errno(m_Mysql);
289 LOG_ERROR("sql.sql", "SQL(p): {}\n [ERROR]: [{}] {}", m_mStmt->getQueryString(), lErrno, mysql_stmt_error(msql_STMT));
290
291 if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection)
292 return _Query(stmt, mysqlStmt, pResult, pRowCount, pFieldCount); // Try again
293
294 m_mStmt->ClearParameters();
295 return false;
296 }
297
298 if (mysql_stmt_execute(msql_STMT))
299 {
300 uint32 lErrno = mysql_errno(m_Mysql);
301 LOG_ERROR("sql.sql", "SQL(p): {}\n [ERROR]: [{}] {}", m_mStmt->getQueryString(), lErrno, mysql_stmt_error(msql_STMT));
302
303 if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection)
304 return _Query(stmt, mysqlStmt, pResult, pRowCount, pFieldCount); // Try again
305
306 m_mStmt->ClearParameters();
307 return false;
308 }
309
310 LOG_DEBUG("sql.sql", "[{} ms] SQL(p): {}", getMSTimeDiff(_s, getMSTime()), m_mStmt->getQueryString());
311
312 m_mStmt->ClearParameters();
313
314 *pResult = reinterpret_cast<MySQLResult*>(mysql_stmt_result_metadata(msql_STMT));
315 *pRowCount = mysql_stmt_affected_rows(msql_STMT);
316 *pFieldCount = mysql_stmt_field_count(msql_STMT);
317
318 return true;
319}
#define ASSERT
Definition: Errors.h:68
#define LOG_DEBUG(filterType__,...)
Definition: Log.h:168
uint32 getMSTime()
Definition: Timer.h:103
uint32 getMSTimeDiff(uint32 oldMSTime, uint32 newMSTime)
Definition: Timer.h:110
MySQLPreparedStatement * GetPreparedStatement(uint32 index)
Definition: MySQLConnection.cpp:502
bool _Query(std::string_view sql, MySQLResult **pResult, MySQLField **pFields, uint64 *pRowCount, uint32 *pFieldCount)
Definition: MySQLConnection.cpp:337
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 
)
338{
339 if (!m_Mysql)
340 return false;
341
342 {
343 uint32 _s = getMSTime();
344
345 if (mysql_query(m_Mysql, std::string(sql).c_str()))
346 {
347 uint32 lErrno = mysql_errno(m_Mysql);
348 LOG_INFO("sql.sql", "SQL: {}", sql);
349 LOG_ERROR("sql.sql", "[{}] {}", lErrno, mysql_error(m_Mysql));
350
351 if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection)
352 return _Query(sql, pResult, pFields, pRowCount, pFieldCount); // We try again
353
354 return false;
355 }
356 else
357 LOG_DEBUG("sql.sql", "[{} ms] SQL: {}", getMSTimeDiff(_s, getMSTime()), sql);
358
359 *pResult = reinterpret_cast<MySQLResult*>(mysql_store_result(m_Mysql));
360 *pRowCount = mysql_affected_rows(m_Mysql);
361 *pFieldCount = mysql_field_count(m_Mysql);
362 }
363
364 if (!*pResult)
365 return false;
366
367 if (!*pRowCount)
368 {
369 mysql_free_result(*pResult);
370 return false;
371 }
372
373 *pFields = reinterpret_cast<MySQLField*>(mysql_fetch_fields(*pResult));
374
375 return true;
376}
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 ( )
379{
380 Execute("START TRANSACTION");
381}
bool Execute(std::string_view sql)
Definition: MySQLConnection.cpp:186

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 ( )
389{
390 Execute("COMMIT");
391}

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 
)
468{
469 return mysql_real_escape_string(m_Mysql, to, from, length);
470}

References m_Mysql.

◆ Execute() [1/2]

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

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)
187{
188 if (!m_Mysql)
189 return false;
190
191 {
192 uint32 _s = getMSTime();
193
194 if (mysql_query(m_Mysql, std::string(sql).c_str()))
195 {
196 uint32 lErrno = mysql_errno(m_Mysql);
197
198 LOG_INFO("sql.sql", "SQL: {}", sql);
199 LOG_ERROR("sql.sql", "[{}] {}", lErrno, mysql_error(m_Mysql));
200
201 if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection)
202 return Execute(sql); // Try again
203
204 return false;
205 }
206 else
207 LOG_DEBUG("sql.sql", "[{} ms] SQL: {}", getMSTimeDiff(_s, getMSTime()), sql);
208 }
209
210 return true;
211}

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)
394{
395 std::vector<SQLElementData> const& queries = transaction->m_queries;
396 if (queries.empty())
397 return -1;
398
400
401 for (auto const& data : queries)
402 {
403 switch (data.type)
404 {
406 {
407 PreparedStatementBase* stmt = nullptr;
408
409 try
410 {
411 stmt = std::get<PreparedStatementBase*>(data.element);
412 }
413 catch (const std::bad_variant_access& ex)
414 {
415 LOG_FATAL("sql.sql", "> PreparedStatementBase not found in SQLElementData. {}", ex.what());
416 ABORT();
417 }
418
419 ASSERT(stmt);
420
421 if (!Execute(stmt))
422 {
423 LOG_WARN("sql.sql", "Transaction aborted. {} queries not executed.", queries.size());
424 int errorCode = GetLastError();
426 return errorCode;
427 }
428 }
429 break;
430 case SQL_ELEMENT_RAW:
431 {
432 std::string sql{};
433
434 try
435 {
436 sql = std::get<std::string>(data.element);
437 }
438 catch (const std::bad_variant_access& ex)
439 {
440 LOG_FATAL("sql.sql", "> std::string not found in SQLElementData. {}", ex.what());
441 ABORT();
442 }
443
444 ASSERT(!sql.empty());
445
446 if (!Execute(sql))
447 {
448 LOG_WARN("sql.sql", "Transaction aborted. {} queries not executed.", queries.size());
449 uint32 errorCode = GetLastError();
451 return errorCode;
452 }
453 }
454 break;
455 }
456 }
457
458 // we might encounter errors during certain queries, and depending on the kind of error
459 // we might want to restart the transaction. So to prevent data loss, we only clean up when it's all done.
460 // This is done in calling functions DatabaseWorkerPool<T>::DirectCommitTransaction and TransactionTask::Execute,
461 // and not while iterating over every element.
462
464 return 0;
465}
@ SQL_ELEMENT_RAW
Definition: SQLOperation.h:28
@ SQL_ELEMENT_PREPARED
Definition: SQLOperation.h:29
#define LOG_WARN(filterType__,...)
Definition: Log.h:160
void CommitTransaction()
Definition: MySQLConnection.cpp:388
void RollbackTransaction()
Definition: MySQLConnection.cpp:383
void BeginTransaction()
Definition: MySQLConnection.cpp:378
uint32 GetLastError()
Definition: MySQLConnection.cpp:477
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 ( )
478{
479 return mysql_errno(m_Mysql);
480}

References m_Mysql.

Referenced by ExecuteTransaction().

◆ GetPreparedStatement()

MySQLPreparedStatement * MySQLConnection::GetPreparedStatement ( uint32  index)
protected
503{
504 ASSERT(index < m_stmts.size(), "Tried to access invalid prepared statement index {} (max index {}) on database `{}`, connection type: {}",
505 index, m_stmts.size(), m_connectionInfo.database, (m_connectionFlags & CONNECTION_ASYNC) ? "asynchronous" : "synchronous");
506
507 MySQLPreparedStatement* ret = m_stmts[index].get();
508
509 if (!ret)
510 LOG_ERROR("sql.sql", "Could not fetch prepared statement {} on database `{}`, connection type: {}.",
511 index, m_connectionInfo.database, (m_connectionFlags & CONNECTION_ASYNC) ? "asynchronous" : "synchronous");
512
513 return ret;
514}

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
498{
499 return mysql_get_server_info(m_Mysql);
500}

References m_Mysql.

◆ GetServerVersion()

uint32 MySQLConnection::GetServerVersion ( ) const
protected
493{
494 return mysql_get_server_version(m_Mysql);
495}

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

483{
484 return m_Mutex.try_lock();
485}
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#if !defined(MARIADB_VERSION_ID) && MYSQL_VERSION_ID >= 80000
134 mysql_ssl_mode opt_use_ssl = SSL_MODE_DISABLED;
135 if (m_connectionInfo.ssl == "ssl")
136 {
137 opt_use_ssl = SSL_MODE_REQUIRED;
138 }
139
140 mysql_options(mysqlInit, MYSQL_OPT_SSL_MODE, (char const*)&opt_use_ssl);
141#else
142 MySQLBool opt_use_ssl = MySQLBool(0);
143 if (m_connectionInfo.ssl == "ssl")
144 {
145 opt_use_ssl = MySQLBool(1);
146 }
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 LOG_INFO("sql.sql", "MySQL client library: {}", mysql_get_client_info());
160 LOG_INFO("sql.sql", "MySQL server ver: {} ", mysql_get_server_info(m_Mysql));
161 }
162
163 LOG_INFO("sql.sql", "Connected to MySQL database at {}", m_connectionInfo.host);
164 mysql_autocommit(m_Mysql, 1);
165
166 // set connection properties to UTF8 to properly handle locales for different
167 // server configs - core sends data in UTF8, so MySQL must expect UTF8 too
168 mysql_set_character_set(m_Mysql, "utf8mb4");
169 return 0;
170 }
171 else
172 {
173 LOG_ERROR("sql.driver", "Could not connect to MySQL database at {}: {}", m_connectionInfo.host, mysql_error(mysqlInit));
174 uint32 errorCode = mysql_errno(mysqlInit);
175 mysql_close(mysqlInit);
176 return errorCode;
177 }
178}
std::remove_pointer_t< decltype(std::declval< MYSQL_BIND >().is_null)> MySQLBool
Definition: MySQLHacks.h:32
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 ( )
473{
474 mysql_ping(m_Mysql);
475}

References m_Mysql.

Referenced by PingOperation::Execute().

◆ PrepareStatement()

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

References DoPrepareStatements(), and m_prepareError.

Referenced by _HandleMySQLErrno().

◆ Query() [1/2]

PreparedResultSet * MySQLConnection::Query ( PreparedStatementBase stmt)
549{
550 MySQLPreparedStatement* mysqlStmt = nullptr;
551 MySQLResult* result = nullptr;
552 uint64 rowCount = 0;
553 uint32 fieldCount = 0;
554
555 if (!_Query(stmt, &mysqlStmt, &result, &rowCount, &fieldCount))
556 return nullptr;
557
558 if (mysql_more_results(m_Mysql))
559 {
560 mysql_next_result(m_Mysql);
561 }
562
563 return new PreparedResultSet(mysqlStmt->GetSTMT(), result, rowCount, fieldCount);
564}
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)
322{
323 if (sql.empty())
324 return nullptr;
325
326 MySQLResult* result = nullptr;
327 MySQLField* fields = nullptr;
328 uint64 rowCount = 0;
329 uint32 fieldCount = 0;
330
331 if (!_Query(sql, &result, &fields, &rowCount, &fieldCount))
332 return nullptr;
333
334 return new ResultSet(result, fields, rowCount, fieldCount);
335}
Definition: QueryResult.h:49

References _Query().

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

◆ RollbackTransaction()

void MySQLConnection::RollbackTransaction ( )
384{
385 Execute("ROLLBACK");
386}

References Execute().

Referenced by ExecuteTransaction().

◆ Unlock()

void MySQLConnection::Unlock ( )
protected

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

488{
489 m_Mutex.unlock();
490}

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