Core/Database: Prepared statement parameter preallocation (#18999)

- Pass prepared statement size to the helper class to prevent runtime resizing.
- Rename CheckValidIndex -> AssertValidIndex
- Cached prepared size on the worker pool as it's shared among all connections
- Cached query data only for each connection, done lookup in map instead of possibly creating a new element
- Kill the prepared statement map, and store raw sql string on the MySQLPreparedStatement class
(This info is only used for logging, and there is no need of keeping a second container just for it)

(cherrypicked from affee140c6)
This commit is contained in:
ariel-
2017-03-01 22:20:53 -03:00
committed by Shauren
parent 60663d1374
commit d131bd1da0
6 changed files with 176 additions and 172 deletions

View File

@@ -199,105 +199,100 @@ bool MySQLConnection::Execute(PreparedStatementBase* stmt)
return false;
uint32 index = stmt->m_index;
MySQLPreparedStatement* m_mStmt = GetPreparedStatement(index);
ASSERT(m_mStmt); // Can only be null if preparation failed, server side error or bad query
m_mStmt->m_stmt = stmt; // Cross reference them for debug output
stmt->BindParameters(m_mStmt);
MYSQL_STMT* msql_STMT = m_mStmt->GetSTMT();
MYSQL_BIND* msql_BIND = m_mStmt->GetBind();
uint32 _s = getMSTime();
if (mysql_stmt_bind_param(msql_STMT, msql_BIND))
{
MySQLPreparedStatement* m_mStmt = GetPreparedStatement(index);
ASSERT(m_mStmt); // Can only be null if preparation failed, server side error or bad query
m_mStmt->m_stmt = stmt; // Cross reference them for debug output
stmt->m_stmt = m_mStmt; /// @todo Cleaner way
uint32 lErrno = mysql_errno(m_Mysql);
TC_LOG_ERROR("sql.sql", "SQL(p): %s\n [ERROR]: [%u] %s", m_mStmt->getQueryString().c_str(), lErrno, mysql_stmt_error(msql_STMT));
stmt->BindParameters();
MYSQL_STMT* msql_STMT = m_mStmt->GetSTMT();
MYSQL_BIND* msql_BIND = m_mStmt->GetBind();
uint32 _s = getMSTime();
if (mysql_stmt_bind_param(msql_STMT, msql_BIND))
{
uint32 lErrno = mysql_errno(m_Mysql);
TC_LOG_ERROR("sql.sql", "SQL(p): %s\n [ERROR]: [%u] %s", m_mStmt->getQueryString(m_queries[index].first).c_str(), lErrno, mysql_stmt_error(msql_STMT));
if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection)
return Execute(stmt); // Try again
m_mStmt->ClearParameters();
return false;
}
if (mysql_stmt_execute(msql_STMT))
{
uint32 lErrno = mysql_errno(m_Mysql);
TC_LOG_ERROR("sql.sql", "SQL(p): %s\n [ERROR]: [%u] %s", m_mStmt->getQueryString(m_queries[index].first).c_str(), lErrno, mysql_stmt_error(msql_STMT));
if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection)
return Execute(stmt); // Try again
m_mStmt->ClearParameters();
return false;
}
TC_LOG_DEBUG("sql.sql", "[%u ms] SQL(p): %s", getMSTimeDiff(_s, getMSTime()), m_mStmt->getQueryString(m_queries[index].first).c_str());
if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection)
return Execute(stmt); // Try again
m_mStmt->ClearParameters();
return true;
return false;
}
if (mysql_stmt_execute(msql_STMT))
{
uint32 lErrno = mysql_errno(m_Mysql);
TC_LOG_ERROR("sql.sql", "SQL(p): %s\n [ERROR]: [%u] %s", m_mStmt->getQueryString().c_str(), lErrno, mysql_stmt_error(msql_STMT));
if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection)
return Execute(stmt); // Try again
m_mStmt->ClearParameters();
return false;
}
TC_LOG_DEBUG("sql.sql", "[%u ms] SQL(p): %s", getMSTimeDiff(_s, getMSTime()), m_mStmt->getQueryString().c_str());
m_mStmt->ClearParameters();
return true;
}
bool MySQLConnection::_Query(PreparedStatementBase* stmt, MYSQL_RES **pResult, uint64* pRowCount, uint32* pFieldCount)
bool MySQLConnection::_Query(PreparedStatementBase* stmt, MYSQL_RES** pResult, uint64* pRowCount, uint32* pFieldCount)
{
if (!m_Mysql)
return false;
uint32 index = stmt->m_index;
MySQLPreparedStatement* m_mStmt = GetPreparedStatement(index);
ASSERT(m_mStmt); // Can only be null if preparation failed, server side error or bad query
m_mStmt->m_stmt = stmt; // Cross reference them for debug output
stmt->BindParameters(m_mStmt);
MYSQL_STMT* msql_STMT = m_mStmt->GetSTMT();
MYSQL_BIND* msql_BIND = m_mStmt->GetBind();
uint32 _s = getMSTime();
if (mysql_stmt_bind_param(msql_STMT, msql_BIND))
{
MySQLPreparedStatement* m_mStmt = GetPreparedStatement(index);
ASSERT(m_mStmt); // Can only be null if preparation failed, server side error or bad query
m_mStmt->m_stmt = stmt; // Cross reference them for debug output
stmt->m_stmt = m_mStmt; /// @todo Cleaner way
uint32 lErrno = mysql_errno(m_Mysql);
TC_LOG_ERROR("sql.sql", "SQL(p): %s\n [ERROR]: [%u] %s", m_mStmt->getQueryString().c_str(), lErrno, mysql_stmt_error(msql_STMT));
stmt->BindParameters();
MYSQL_STMT* msql_STMT = m_mStmt->GetSTMT();
MYSQL_BIND* msql_BIND = m_mStmt->GetBind();
uint32 _s = getMSTime();
if (mysql_stmt_bind_param(msql_STMT, msql_BIND))
{
uint32 lErrno = mysql_errno(m_Mysql);
TC_LOG_ERROR("sql.sql", "SQL(p): %s\n [ERROR]: [%u] %s", m_mStmt->getQueryString(m_queries[index].first).c_str(), lErrno, mysql_stmt_error(msql_STMT));
if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection)
return _Query(stmt, pResult, pRowCount, pFieldCount); // Try again
m_mStmt->ClearParameters();
return false;
}
if (mysql_stmt_execute(msql_STMT))
{
uint32 lErrno = mysql_errno(m_Mysql);
TC_LOG_ERROR("sql.sql", "SQL(p): %s\n [ERROR]: [%u] %s",
m_mStmt->getQueryString(m_queries[index].first).c_str(), lErrno, mysql_stmt_error(msql_STMT));
if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection)
return _Query(stmt, pResult, pRowCount, pFieldCount); // Try again
m_mStmt->ClearParameters();
return false;
}
TC_LOG_DEBUG("sql.sql", "[%u ms] SQL(p): %s", getMSTimeDiff(_s, getMSTime()), m_mStmt->getQueryString(m_queries[index].first).c_str());
if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection)
return _Query(stmt, pResult, pRowCount, pFieldCount); // Try again
m_mStmt->ClearParameters();
*pResult = mysql_stmt_result_metadata(msql_STMT);
*pRowCount = mysql_stmt_num_rows(msql_STMT);
*pFieldCount = mysql_stmt_field_count(msql_STMT);
return true;
return false;
}
if (mysql_stmt_execute(msql_STMT))
{
uint32 lErrno = mysql_errno(m_Mysql);
TC_LOG_ERROR("sql.sql", "SQL(p): %s\n [ERROR]: [%u] %s",
m_mStmt->getQueryString().c_str(), lErrno, mysql_stmt_error(msql_STMT));
if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection)
return _Query(stmt, pResult, pRowCount, pFieldCount); // Try again
m_mStmt->ClearParameters();
return false;
}
TC_LOG_DEBUG("sql.sql", "[%u ms] SQL(p): %s", getMSTimeDiff(_s, getMSTime()), m_mStmt->getQueryString().c_str());
m_mStmt->ClearParameters();
*pResult = mysql_stmt_result_metadata(msql_STMT);
*pRowCount = mysql_stmt_num_rows(msql_STMT);
*pFieldCount = mysql_stmt_field_count(msql_STMT);
return true;
}
ResultSet* MySQLConnection::Query(const char* sql)
@@ -454,10 +449,8 @@ MySQLPreparedStatement* MySQLConnection::GetPreparedStatement(uint32 index)
return ret;
}
void MySQLConnection::PrepareStatement(uint32 index, const char* sql, ConnectionFlags flags)
void MySQLConnection::PrepareStatement(uint32 index, std::string const& sql, ConnectionFlags flags)
{
m_queries.insert(PreparedStatementMap::value_type(index, std::make_pair(sql, flags)));
// Check if specified query should be prepared on this connection
// i.e. don't prepare async statements on synchronous connections
// to save memory that will not be used.
@@ -470,23 +463,21 @@ void MySQLConnection::PrepareStatement(uint32 index, const char* sql, Connection
MYSQL_STMT* stmt = mysql_stmt_init(m_Mysql);
if (!stmt)
{
TC_LOG_ERROR("sql.sql", "In mysql_stmt_init() id: %u, sql: \"%s\"", index, sql);
TC_LOG_ERROR("sql.sql", "In mysql_stmt_init() id: %u, sql: \"%s\"", index, sql.c_str());
TC_LOG_ERROR("sql.sql", "%s", mysql_error(m_Mysql));
m_prepareError = true;
}
else
{
if (mysql_stmt_prepare(stmt, sql, static_cast<unsigned long>(strlen(sql))))
if (mysql_stmt_prepare(stmt, sql.c_str(), static_cast<unsigned long>(sql.size())))
{
TC_LOG_ERROR("sql.sql", "In mysql_stmt_prepare() id: %u, sql: \"%s\"", index, sql);
TC_LOG_ERROR("sql.sql", "In mysql_stmt_prepare() id: %u, sql: \"%s\"", index, sql.c_str());
TC_LOG_ERROR("sql.sql", "%s", mysql_stmt_error(stmt));
mysql_stmt_close(stmt);
m_prepareError = true;
}
else
{
m_stmts[index] = Trinity::make_unique<MySQLPreparedStatement>(stmt);
}
m_stmts[index] = Trinity::make_unique<MySQLPreparedStatement>(stmt, sql);
}
}