AzeorthCore 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)
 
size_t EscapeString (char *to, const char *from, 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
 
MySQLPreparedStatementGetPreparedStatement (uint32 index)
 
void PrepareStatement (uint32 index, std::string_view sql, ConnectionFlags flags)
 
virtual void DoPrepareStatements ()=0
 

Protected Attributes

PreparedStatementContainer m_stmts
 
bool m_reconnecting
 PreparedStatements storage. More...
 
bool m_prepareError
 Are we reconnecting? More...
 

Private Member Functions

bool _HandleMySQLErrno (uint32 errNo, uint8 attempts=5)
 Was there any error while preparing statements? More...
 
 MySQLConnection (MySQLConnection const &right)=delete
 
MySQLConnectionoperator= (MySQLConnection const &right)=delete
 

Private Attributes

ProducerConsumerQueue< SQLOperation * > * m_queue
 
std::unique_ptr< DatabaseWorkerm_worker
 Queue shared with other asynchronous connections. More...
 
MySQLHandlem_Mysql
 Core worker task. More...
 
MySQLConnectionInfom_connectionInfo
 MySQL Handle. 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_queue(nullptr),
55 m_Mysql(nullptr),
56 m_connectionInfo(connInfo),
@ CONNECTION_SYNCH
Definition: MySQLConnection.h:39
ProducerConsumerQueue< SQLOperation * > * m_queue
Definition: MySQLConnection.h:111
MySQLConnectionInfo & m_connectionInfo
MySQL Handle.
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:106
MySQLHandle * m_Mysql
Core worker task.
Definition: MySQLConnection.h:113
bool m_reconnecting
PreparedStatements storage.
Definition: MySQLConnection.h:105

◆ 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_queue(queue),
63 m_Mysql(nullptr),
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:112

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 
)
private

Was there any error while preparing statements?

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

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

References m_Mysql, m_stmts, and m_worker.

Referenced by ~MySQLConnection().

◆ CommitTransaction()

void MySQLConnection::CommitTransaction ( )
381{
382 Execute("COMMIT");
383}

References Execute().

Referenced by ExecuteTransaction().

◆ DoPrepareStatements()

virtual void MySQLConnection::DoPrepareStatements ( )
protectedpure virtual

◆ EscapeString()

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

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 (mysql_stmt_bind_param(msql_STMT, msql_BIND))
231 {
232 uint32 lErrno = mysql_errno(m_Mysql);
233 LOG_ERROR("sql.sql", "SQL(p): {}\n [ERROR]: [{}] {}", m_mStmt->getQueryString(), lErrno, mysql_stmt_error(msql_STMT));
234
235 if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection)
236 return Execute(stmt); // Try again
237
238 m_mStmt->ClearParameters();
239 return false;
240 }
241
242 if (mysql_stmt_execute(msql_STMT))
243 {
244 uint32 lErrno = mysql_errno(m_Mysql);
245 LOG_ERROR("sql.sql", "SQL(p): {}\n [ERROR]: [{}] {}", m_mStmt->getQueryString(), lErrno, mysql_stmt_error(msql_STMT));
246
247 if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection)
248 return Execute(stmt); // Try again
249
250 m_mStmt->ClearParameters();
251 return false;
252 }
253
254 LOG_DEBUG("sql.sql", "[{} ms] SQL(p): {}", getMSTimeDiff(_s, getMSTime()), m_mStmt->getQueryString());
255
256 m_mStmt->ClearParameters();
257 return true;
258}

References _HandleMySQLErrno(), ASSERT, MySQLPreparedStatement::BindParameters(), MySQLPreparedStatement::ClearParameters(), Execute(), MySQLPreparedStatement::GetBind(), PreparedStatementBase::GetIndex(), getMSTime(), getMSTimeDiff(), 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)
386{
387 std::vector<SQLElementData> const& queries = transaction->m_queries;
388 if (queries.empty())
389 return -1;
390
392
393 for (auto const& data : queries)
394 {
395 switch (data.type)
396 {
398 {
399 PreparedStatementBase* stmt = nullptr;
400
401 try
402 {
403 stmt = std::get<PreparedStatementBase*>(data.element);
404 }
405 catch (const std::bad_variant_access& ex)
406 {
407 LOG_FATAL("sql.sql", "> PreparedStatementBase not found in SQLElementData. {}", ex.what());
408 ABORT();
409 }
410
411 ASSERT(stmt);
412
413 if (!Execute(stmt))
414 {
415 LOG_WARN("sql.sql", "Transaction aborted. {} queries not executed.", queries.size());
416 int errorCode = GetLastError();
418 return errorCode;
419 }
420 }
421 break;
422 case SQL_ELEMENT_RAW:
423 {
424 std::string sql{};
425
426 try
427 {
428 sql = std::get<std::string>(data.element);
429 }
430 catch (const std::bad_variant_access& ex)
431 {
432 LOG_FATAL("sql.sql", "> std::string not found in SQLElementData. {}", ex.what());
433 ABORT();
434 }
435
436 ASSERT(!sql.empty());
437
438 if (!Execute(sql))
439 {
440 LOG_WARN("sql.sql", "Transaction aborted. {} queries not executed.", queries.size());
441 uint32 errorCode = GetLastError();
443 return errorCode;
444 }
445 }
446 break;
447 }
448 }
449
450 // we might encounter errors during certain queries, and depending on the kind of error
451 // we might want to restart the transaction. So to prevent data loss, we only clean up when it's all done.
452 // This is done in calling functions DatabaseWorkerPool<T>::DirectCommitTransaction and TransactionTask::Execute,
453 // and not while iterating over every element.
454
456 return 0;
457}
#define ABORT
Definition: Errors.h:76
#define LOG_WARN(filterType__,...)
Definition: Log.h:163
@ SQL_ELEMENT_RAW
Definition: SQLOperation.h:28
@ SQL_ELEMENT_PREPARED
Definition: SQLOperation.h:29
void CommitTransaction()
Definition: MySQLConnection.cpp:380
void RollbackTransaction()
Definition: MySQLConnection.cpp:375
void BeginTransaction()
Definition: MySQLConnection.cpp:370
uint32 GetLastError()
Definition: MySQLConnection.cpp:469
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 ( )
470{
471 return mysql_errno(m_Mysql);
472}

References m_Mysql.

Referenced by ExecuteTransaction().

◆ GetPreparedStatement()

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

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

Referenced by _Query(), and Execute().

◆ GetServerVersion()

uint32 MySQLConnection::GetServerVersion ( ) const
protected
485{
486 return mysql_get_server_version(m_Mysql);
487}

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

475{
476 return m_Mutex.try_lock();
477}
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 ( )
465{
466 mysql_ping(m_Mysql);
467}

References m_Mysql.

Referenced by PingOperation::Execute().

◆ PrepareStatement()

void MySQLConnection::PrepareStatement ( uint32  index,
std::string_view  sql,
ConnectionFlags  flags 
)
protected
504{
505 // Check if specified query should be prepared on this connection
506 // i.e. don't prepare async statements on synchronous connections
507 // to save memory that will not be used.
508 if (!(m_connectionFlags & flags))
509 {
510 m_stmts[index].reset();
511 return;
512 }
513
514 MYSQL_STMT* stmt = mysql_stmt_init(m_Mysql);
515 if (!stmt)
516 {
517 LOG_ERROR("sql.sql", "In mysql_stmt_init() id: {}, sql: \"{}\"", index, sql);
518 LOG_ERROR("sql.sql", "{}", mysql_error(m_Mysql));
519 m_prepareError = true;
520 }
521 else
522 {
523 if (mysql_stmt_prepare(stmt, std::string(sql).c_str(), static_cast<unsigned long>(sql.size())))
524 {
525 LOG_ERROR("sql.sql", "In mysql_stmt_prepare() id: {}, sql: \"{}\"", index, sql);
526 LOG_ERROR("sql.sql", "{}", mysql_stmt_error(stmt));
527 mysql_stmt_close(stmt);
528 m_prepareError = true;
529 }
530 else
531 m_stmts[index] = std::make_unique<MySQLPreparedStatement>(reinterpret_cast<MySQLStmt*>(stmt), sql);
532 }
533}
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)
536{
537 MySQLPreparedStatement* mysqlStmt = nullptr;
538 MySQLResult* result = nullptr;
539 uint64 rowCount = 0;
540 uint32 fieldCount = 0;
541
542 if (!_Query(stmt, &mysqlStmt, &result, &rowCount, &fieldCount))
543 return nullptr;
544
545 if (mysql_more_results(m_Mysql))
546 {
547 mysql_next_result(m_Mysql);
548 }
549
550 return new PreparedResultSet(mysqlStmt->GetSTMT(), result, rowCount, fieldCount);
551}
std::uint64_t uint64
Definition: Define.h:107
Definition: QueryResult.h:99

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

◆ Query() [2/2]

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

References _Query().

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

◆ RollbackTransaction()

void MySQLConnection::RollbackTransaction ( )
376{
377 Execute("ROLLBACK");
378}

References Execute().

Referenced by ExecuteTransaction().

◆ Unlock()

void MySQLConnection::Unlock ( )
protected

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

480{
481 m_Mutex.unlock();
482}

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

◆ 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
private

◆ m_prepareError

bool MySQLConnection::m_prepareError
protected

Are we reconnecting?

Referenced by PrepareStatement(), and PrepareStatements().

◆ m_queue

ProducerConsumerQueue<SQLOperation*>* MySQLConnection::m_queue
private

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