diff options
author | Machiavelli <none@none> | 2010-09-24 22:16:21 +0200 |
---|---|---|
committer | Machiavelli <none@none> | 2010-09-24 22:16:21 +0200 |
commit | 3c6dc320308880bde4ef9eddd695db28a74aa0d9 (patch) | |
tree | f209e6c487e436fc1cd978487dddf3604ce2b594 /src/server/shared/Database/MySQLConnection.cpp | |
parent | b46b498141cc167163c6112e8e2bfa32fec2d7dc (diff) |
Core/DBLayer:
- Rewrite Field class to be able to store both binary prepared statement data and data from adhoc query resultsets
- Buffer the data of prepared statements using ResultSet and Field classes and let go of mysql c api structures after PreparedResultSet constructor. Fixes a race condition and thus a possible crash/data corruption (issue pointed out to Derex, basic suggestion by raczman)
- Conform PreparedResultSet and ResultSet to the same design standards, and using Field class as data buffer class for both
* NOTE: This means the fetching methods are uniform again, using ¨Field* fields = result->Fetch();¨ and access to elements trough fields[x].
* NOTE: for access to the correct row in prepared statements, ¨Field* fields = result->Fetch();¨ must ALWAYS be called inside the do { }while(result->NextRow()) loop.
* NOTE: This means that Field::GetString() returns std::string object and Field::GetCString() returns const char* pointer.
Still experimental and all that jazz, not recommended for production servers until feedback is given.
--HG--
branch : trunk
Diffstat (limited to 'src/server/shared/Database/MySQLConnection.cpp')
-rw-r--r-- | src/server/shared/Database/MySQLConnection.cpp | 70 |
1 files changed, 63 insertions, 7 deletions
diff --git a/src/server/shared/Database/MySQLConnection.cpp b/src/server/shared/Database/MySQLConnection.cpp index 54bf97ce601..f3fa2f352da 100644 --- a/src/server/shared/Database/MySQLConnection.cpp +++ b/src/server/shared/Database/MySQLConnection.cpp @@ -222,14 +222,63 @@ bool MySQLConnection::Execute(PreparedStatement* stmt) m_mStmt->ClearParameters(); return false; } - else + + #ifdef SQLQUERY_LOG + sLog.outSQLDriver("[%u ms] Prepared SQL: %u", getMSTimeDiff(_s, getMSTime()), index); + #endif + m_mStmt->ClearParameters(); + return true; + } +} + +bool MySQLConnection::_Query(PreparedStatement* stmt, MYSQL_RES **pResult, MYSQL_FIELD **pFields, uint64* pRowCount, uint32* pFieldCount) +{ + if (!m_Mysql) + return false; + + uint32 index = stmt->m_index; + { + // guarded block for thread-safe mySQL request + ACE_Guard<ACE_Thread_Mutex> query_connection_guard(m_Mutex); + + 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 + + stmt->BindParameters(); + + MYSQL_STMT* msql_STMT = m_mStmt->GetSTMT(); + MYSQL_BIND* msql_BIND = m_mStmt->GetBind(); + + #ifdef SQLQUERY_LOG + uint32 _s = getMSTime(); + #endif + if (mysql_stmt_bind_param(msql_STMT, msql_BIND)) { - #ifdef SQLQUERY_LOG - sLog.outSQLDriver("[%u ms] Prepared SQL: %u", getMSTimeDiff(_s, getMSTime()), index); - #endif + sLog.outSQLDriver("[ERROR]: PreparedStatement (id: %u) error binding params: %s", index, mysql_stmt_error(msql_STMT)); + m_mStmt->ClearParameters(); + return false; + } + + if (mysql_stmt_execute(msql_STMT)) + { + sLog.outSQLDriver("[ERROR]: PreparedStatement (id: %u) error executing: %s", index, mysql_stmt_error(msql_STMT)); m_mStmt->ClearParameters(); - return true; + return false; } + + #ifdef SQLQUERY_LOG + sLog.outSQLDriver("[%u ms] Prepared SQL: %u", getMSTimeDiff(_s, getMSTime()), index); + #endif + m_mStmt->ClearParameters(); + + *pResult = mysql_stmt_result_metadata(msql_STMT); + *pRowCount = /*mysql_affected_rows(m_Mysql); //* or*/ mysql_stmt_num_rows(msql_STMT); + *pFieldCount = mysql_stmt_field_count(msql_STMT); + + return true; + } } @@ -336,10 +385,17 @@ void MySQLConnection::PrepareStatement(uint32 index, const char* sql) PreparedResultSet* MySQLConnection::Query(PreparedStatement* stmt) { - this->Execute(stmt); + MYSQL_RES *result = NULL; + MYSQL_FIELD *fields = NULL; + uint64 rowCount = 0; + uint32 fieldCount = 0; + + if (!_Query(stmt, &result, &fields, &rowCount, &fieldCount)) + return NULL; + if (mysql_more_results(m_Mysql)) { mysql_next_result(m_Mysql); } - return new PreparedResultSet(stmt->m_stmt->GetSTMT()); + return new PreparedResultSet(stmt->m_stmt->GetSTMT(), result, fields, rowCount, fieldCount); } |