32#include <mysqld_error.h>
38 if (tokens.size() != 5 && tokens.size() != 6)
41 host.assign(tokens[0]);
43 user.assign(tokens[2]);
47 if (tokens.size() == 6)
48 ssl.assign(tokens[5]);
54 boost::asio::executor_work_guard<Trinity::Asio::IoContext::Executor>
WorkGuard;
61m_connectionInfo(connInfo),
62m_connectionFlags(connectionFlags)
93 mysqlInit = mysql_init(
nullptr);
97 return CR_UNKNOWN_ERROR;
101 char const* unix_socket =
nullptr;
104 mysql_options(mysqlInit, MYSQL_SET_CHARSET_NAME,
"utf8mb4");
112#if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS
113 unsigned int opt = MYSQL_PROTOCOL_PIPE;
117 unsigned int opt = MYSQL_PROTOCOL_SOCKET;
119 mysql_options(mysqlInit, MYSQL_OPT_PROTOCOL, (
char const*)&opt);
121#if !defined(MARIADB_VERSION_ID) && MYSQL_VERSION_ID >= 80000
129 mysql_options(mysqlInit, MYSQL_OPT_GET_SERVER_PUBLIC_KEY, (
char const*)&geterverPublicKey);
135#if !defined(MARIADB_VERSION_ID) && MYSQL_VERSION_ID >= 80000
136 mysql_ssl_mode opt_use_ssl = SSL_MODE_DISABLED;
139 opt_use_ssl = SSL_MODE_REQUIRED;
141 mysql_options(mysqlInit, MYSQL_OPT_SSL_MODE, (
char const*)&opt_use_ssl);
148 mysql_options(mysqlInit, MYSQL_OPT_SSL_ENFORCE, (
char const*)&opt_use_ssl);
159 TC_LOG_INFO(
"sql.sql",
"MySQL client library: {}", mysql_get_client_info());
171 mysql_set_character_set(
m_Mysql,
"utf8mb4");
177 uint32 errorCode = mysql_errno(mysqlInit);
178 mysql_close(mysqlInit);
218#if TRINITY_COMPILER == TRINITY_COMPILER_GNU
219#pragma GCC diagnostic push
220#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
223#pragma warning(disable: 4996)
226 return mysql_stmt_bind_param(stmt, bnd);
228#if TRINITY_COMPILER == TRINITY_COMPILER_GNU
229#pragma GCC diagnostic pop
247 MYSQL_STMT* msql_STMT = m_mStmt->
GetSTMT();
248 MYSQL_BIND* msql_BIND = m_mStmt->
GetBind();
264 if (mysql_stmt_execute(msql_STMT))
293 *mysqlStmt = m_mStmt;
295 MYSQL_STMT* msql_STMT = m_mStmt->
GetSTMT();
296 MYSQL_BIND* msql_BIND = m_mStmt->
GetBind();
306 return _Query(stmt, mysqlStmt, pResult, pRowCount, pFieldCount);
312 if (mysql_stmt_execute(msql_STMT))
315 TC_LOG_ERROR(
"sql.sql",
"SQL(p): {}\n [ERROR]: [{}] {}",
319 return _Query(stmt, mysqlStmt, pResult, pRowCount, pFieldCount);
329 *pResult =
reinterpret_cast<MySQLResult*
>(mysql_stmt_result_metadata(msql_STMT));
330 *pRowCount = mysql_stmt_num_rows(msql_STMT);
331 *pFieldCount = mysql_stmt_field_count(msql_STMT);
346 if (!
_Query(sql, &result, &fields, &rowCount, &fieldCount))
349 return new ResultSet(result, fields, rowCount, fieldCount);
367 return _Query(sql, pResult, pFields, pRowCount, pFieldCount);
375 *pRowCount = mysql_affected_rows(
m_Mysql);
376 *pFieldCount = mysql_field_count(
m_Mysql);
384 mysql_free_result(*pResult);
388 *pFields =
reinterpret_cast<MySQLField*
>(mysql_fetch_fields(*pResult));
410 std::vector<TransactionData>
const& queries = transaction->m_queries;
416 for (
auto itr = queries.begin(); itr != queries.end(); ++itr)
420 TC_LOG_WARN(
"sql.sql",
"Transaction aborted. {} queries not executed.", queries.size());
438 return mysql_real_escape_string(
m_Mysql, to, from, length);
453 boost::asio::executor_work_guard executorWorkGuard = boost::asio::make_work_guard(context->
get_executor());
457 .WorkGuard = std::move(executorWorkGuard)
481 return mysql_get_server_version(
m_Mysql);
486 ASSERT(index <
m_stmts.size(),
"Tried to access invalid prepared statement index %u (max index " SZFMTD ") on database `%s`, connection type: %s",
490 TC_LOG_ERROR(
"sql.sql",
"Could not fetch prepared statement {} on database `{}`, connection type: {}.",
507 MYSQL_STMT* stmt = mysql_stmt_init(
m_Mysql);
510 TC_LOG_ERROR(
"sql.sql",
"In mysql_stmt_init() id: {}, sql: \"{}\"", index, sql);
516 if (mysql_stmt_prepare(stmt, sql.data(),
static_cast<unsigned long>(sql.size())))
518 TC_LOG_ERROR(
"sql.sql",
"In mysql_stmt_prepare() id: {}, sql: \"{}\"", index, sql);
520 mysql_stmt_close(stmt);
524 m_stmts[index] = std::make_unique<MySQLPreparedStatement>(
reinterpret_cast<MySQLStmt*
>(stmt), std::string(sql));
535 if (!
_Query(stmt, &mysqlStmt, &result, &rowCount, &fieldCount))
538 if (mysql_more_results(
m_Mysql))
549 case CR_SERVER_GONE_ERROR:
551 case CR_SERVER_LOST_EXTENDED:
555 TC_LOG_ERROR(
"sql.sql",
"Lost the connection to the MySQL server!");
562 case CR_CONN_HOST_ERROR:
564 TC_LOG_INFO(
"sql.sql",
"Attempting to reconnect to the MySQL server...");
574 TC_LOG_FATAL(
"sql.sql",
"Could not re-prepare statements!");
575 std::this_thread::sleep_for(std::chrono::seconds(10));
579 TC_LOG_INFO(
"sql.sql",
"Successfully reconnected to {} @{}:{} ({}).",
587 if ((--attempts) == 0)
591 TC_LOG_FATAL(
"sql.sql",
"Failed to reconnect to the MySQL server, "
592 "terminating the server to prevent data corruption!");
595 std::this_thread::sleep_for(std::chrono::seconds(10));
602 std::this_thread::sleep_for(std::chrono::seconds(3));
607 case ER_LOCK_DEADLOCK:
610 case ER_WRONG_VALUE_COUNT:
615 case ER_BAD_FIELD_ERROR:
616 case ER_NO_SUCH_TABLE:
617 TC_LOG_ERROR(
"sql.sql",
"Your database structure is not up to date. Please make sure you've executed all queries in the sql/updates folders.");
618 std::this_thread::sleep_for(std::chrono::seconds(10));
622 TC_LOG_ERROR(
"sql.sql",
"Error while parsing SQL. Core fix required.");
623 std::this_thread::sleep_for(std::chrono::seconds(10));
627 TC_LOG_ERROR(
"sql.sql",
"Unhandled MySQL errno {}. Unexpected behaviour possible.", errNo);
#define TC_LOG_DEBUG(filterType__, message__,...)
#define TC_LOG_ERROR(filterType__, message__,...)
#define TC_LOG_FATAL(filterType__, message__,...)
#define TC_LOG_INFO(filterType__, message__,...)
#define TC_LOG_WARN(filterType__, message__,...)
static auto mysql_bind_param_no_deprecated(MYSQL_STMT *stmt, MYSQL_BIND *bnd)
std::remove_pointer_t< decltype(std::declval< MYSQL_BIND >().is_null)> MySQLBool
uint32 getMSTimeDiff(uint32 oldMSTime, uint32 newMSTime)
std::unique_ptr< WorkerThread > m_workerThread
Core worker thread.
std::thread::id GetWorkerThreadId() const
bool Execute(char const *sql)
void PrepareStatement(uint32 index, std::string_view sql, ConnectionFlags flags)
MySQLPreparedStatement * GetPreparedStatement(uint32 index)
int ExecuteTransaction(std::shared_ptr< TransactionBase > transaction)
MySQLConnectionInfo & m_connectionInfo
Connection info (used for logging)
void RollbackTransaction()
PreparedStatementContainer m_stmts
PreparedStatements storage.
size_t EscapeString(char *to, const char *from, size_t length)
uint32 GetServerVersion() const
MySQLConnection(MySQLConnectionInfo &connInfo, ConnectionFlags connectionFlags)
ResultSet * Query(char const *sql)
bool _Query(char const *sql, MySQLResult **pResult, MySQLField **pFields, uint64 *pRowCount, uint32 *pFieldCount)
ConnectionFlags m_connectionFlags
Connection flags (for preparing relevant statements)
bool _HandleMySQLErrno(uint32 errNo, uint8 attempts=5)
void Unlock()
Called by parent databasepool. Will let other threads access this connection.
bool m_prepareError
Was there any error while preparing statements?
MySQLHandle * m_Mysql
MySQL Handle.
virtual ~MySQLConnection()
virtual void DoPrepareStatements()=0
void StartWorkerThread(Trinity::Asio::IoContext *context)
bool m_reconnecting
Are we reconnecting?
std::string getQueryString() const
void BindParameters(PreparedStatementBase *stmt)
Executor get_executor() noexcept
TC_COMMON_API std::vector< std::string_view > Tokenize(std::string_view str, char sep, bool keepEmpty)
std::string port_or_socket
MySQLConnectionInfo(std::string const &infoString)
boost::asio::executor_work_guard< Trinity::Asio::IoContext::Executor > WorkGuard
static PreparedStatementBase * ToExecutable(std::unique_ptr< PreparedStatementBase > const &stmt)