31#include <mysqld_error.h>
37 if (tokens.size() != 5 && tokens.size() != 6)
40 host.assign(tokens[0]);
42 user.assign(tokens[2]);
46 if (tokens.size() == 6)
47 ssl.assign(tokens[5]);
54m_connectionInfo(connInfo),
55m_connectionFlags(connectionFlags)
85 mysqlInit = mysql_init(
nullptr);
89 return CR_UNKNOWN_ERROR;
93 char const* unix_socket;
96 mysql_options(mysqlInit, MYSQL_SET_CHARSET_NAME,
"utf8mb4");
101 unsigned int opt = MYSQL_PROTOCOL_PIPE;
102 mysql_options(mysqlInit, MYSQL_OPT_PROTOCOL, (
char const*)&opt);
104 unix_socket =
nullptr;
109 unix_socket =
nullptr;
114 unsigned int opt = MYSQL_PROTOCOL_SOCKET;
115 mysql_options(mysqlInit, MYSQL_OPT_PROTOCOL, (
char const*)&opt);
123 unix_socket =
nullptr;
129#if !defined(MARIADB_VERSION_ID) && MYSQL_VERSION_ID >= 80000
130 mysql_ssl_mode opt_use_ssl = SSL_MODE_DISABLED;
133 opt_use_ssl = SSL_MODE_REQUIRED;
135 mysql_options(mysqlInit, MYSQL_OPT_SSL_MODE, (
char const*)&opt_use_ssl);
142 mysql_options(mysqlInit, MYSQL_OPT_SSL_ENFORCE, (
char const*)&opt_use_ssl);
153 TC_LOG_INFO(
"sql.sql",
"MySQL client library: {}", mysql_get_client_info());
165 mysql_set_character_set(
m_Mysql,
"utf8mb4");
171 uint32 errorCode = mysql_errno(mysqlInit);
172 mysql_close(mysqlInit);
212#if TRINITY_COMPILER == TRINITY_COMPILER_GNU
213#pragma GCC diagnostic push
214#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
217#pragma warning(disable: 4996)
220 return mysql_stmt_bind_param(stmt, bnd);
222#if TRINITY_COMPILER == TRINITY_COMPILER_GNU
223#pragma GCC diagnostic pop
241 MYSQL_STMT* msql_STMT = m_mStmt->
GetSTMT();
242 MYSQL_BIND* msql_BIND = m_mStmt->
GetBind();
258 if (mysql_stmt_execute(msql_STMT))
287 *mysqlStmt = m_mStmt;
289 MYSQL_STMT* msql_STMT = m_mStmt->
GetSTMT();
290 MYSQL_BIND* msql_BIND = m_mStmt->
GetBind();
300 return _Query(stmt, mysqlStmt, pResult, pRowCount, pFieldCount);
306 if (mysql_stmt_execute(msql_STMT))
309 TC_LOG_ERROR(
"sql.sql",
"SQL(p): {}\n [ERROR]: [{}] {}",
313 return _Query(stmt, mysqlStmt, pResult, pRowCount, pFieldCount);
323 *pResult =
reinterpret_cast<MySQLResult*
>(mysql_stmt_result_metadata(msql_STMT));
324 *pRowCount = mysql_stmt_num_rows(msql_STMT);
325 *pFieldCount = mysql_stmt_field_count(msql_STMT);
340 if (!
_Query(sql, &result, &fields, &rowCount, &fieldCount))
343 return new ResultSet(result, fields, rowCount, fieldCount);
361 return _Query(sql, pResult, pFields, pRowCount, pFieldCount);
369 *pRowCount = mysql_affected_rows(
m_Mysql);
370 *pFieldCount = mysql_field_count(
m_Mysql);
378 mysql_free_result(*pResult);
382 *pFields =
reinterpret_cast<MySQLField*
>(mysql_fetch_fields(*pResult));
404 std::vector<TransactionData>
const& queries = transaction->m_queries;
410 for (
auto itr = queries.begin(); itr != queries.end(); ++itr)
414 TC_LOG_WARN(
"sql.sql",
"Transaction aborted. {} queries not executed.", queries.size());
432 return mysql_real_escape_string(
m_Mysql, to, from, length);
449 boost::asio::executor_work_guard executorWorkGuard = boost::asio::make_work_guard(context->
get_executor());
475 return mysql_get_server_version(
m_Mysql);
480 ASSERT(index <
m_stmts.size(),
"Tried to access invalid prepared statement index %u (max index " SZFMTD ") on database `%s`, connection type: %s",
484 TC_LOG_ERROR(
"sql.sql",
"Could not fetch prepared statement {} on database `{}`, connection type: {}.",
501 MYSQL_STMT* stmt = mysql_stmt_init(
m_Mysql);
504 TC_LOG_ERROR(
"sql.sql",
"In mysql_stmt_init() id: {}, sql: \"{}\"", index, sql);
510 if (mysql_stmt_prepare(stmt, sql.data(),
static_cast<unsigned long>(sql.size())))
512 TC_LOG_ERROR(
"sql.sql",
"In mysql_stmt_prepare() id: {}, sql: \"{}\"", index, sql);
514 mysql_stmt_close(stmt);
518 m_stmts[index] = std::make_unique<MySQLPreparedStatement>(
reinterpret_cast<MySQLStmt*
>(stmt), std::string(sql));
529 if (!
_Query(stmt, &mysqlStmt, &result, &rowCount, &fieldCount))
532 if (mysql_more_results(
m_Mysql))
543 case CR_SERVER_GONE_ERROR:
545 case CR_SERVER_LOST_EXTENDED:
549 TC_LOG_ERROR(
"sql.sql",
"Lost the connection to the MySQL server!");
556 case CR_CONN_HOST_ERROR:
558 TC_LOG_INFO(
"sql.sql",
"Attempting to reconnect to the MySQL server...");
568 TC_LOG_FATAL(
"sql.sql",
"Could not re-prepare statements!");
569 std::this_thread::sleep_for(std::chrono::seconds(10));
573 TC_LOG_INFO(
"sql.sql",
"Successfully reconnected to {} @{}:{} ({}).",
581 if ((--attempts) == 0)
585 TC_LOG_FATAL(
"sql.sql",
"Failed to reconnect to the MySQL server, "
586 "terminating the server to prevent data corruption!");
589 std::this_thread::sleep_for(std::chrono::seconds(10));
596 std::this_thread::sleep_for(std::chrono::seconds(3));
601 case ER_LOCK_DEADLOCK:
604 case ER_WRONG_VALUE_COUNT:
609 case ER_BAD_FIELD_ERROR:
610 case ER_NO_SUCH_TABLE:
611 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.");
612 std::this_thread::sleep_for(std::chrono::seconds(10));
616 TC_LOG_ERROR(
"sql.sql",
"Error while parsing SQL. Core fix required.");
617 std::this_thread::sleep_for(std::chrono::seconds(10));
621 TC_LOG_ERROR(
"sql.sql",
"Unhandled MySQL errno {}. Unexpected behaviour possible.", errNo);
#define TC_LOG_WARN(filterType__,...)
#define TC_LOG_DEBUG(filterType__,...)
#define TC_LOG_ERROR(filterType__,...)
#define TC_LOG_INFO(filterType__,...)
#define TC_LOG_FATAL(filterType__,...)
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::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)
std::unique_ptr< std::thread > m_workerThread
Core worker thread.
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)
static PreparedStatementBase * ToExecutable(std::unique_ptr< PreparedStatementBase > const &stmt)