Skip to content

Commit

Permalink
Fixed a memory leak when using prepared queries
Browse files Browse the repository at this point in the history
  • Loading branch information
FredyH committed Aug 11, 2021
1 parent e750350 commit 0d0191f
Show file tree
Hide file tree
Showing 3 changed files with 10 additions and 9 deletions.
2 changes: 1 addition & 1 deletion MySQLOO/include/ResultData.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class ResultDataRow {
class ResultData {
public:
ResultData(MYSQL_RES* result);
ResultData(MYSQL_STMT* result);
ResultData(MYSQL_STMT* result, MYSQL_RES* metaData);
ResultData();
~ResultData();
std::vector<std::string> & getColumns() { return columns; }
Expand Down
10 changes: 7 additions & 3 deletions MySQLOO/source/PreparedQuery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -266,18 +266,22 @@ void PreparedQuery::executeQuery(MYSQL* connection, std::shared_ptr<IQueryData>
data->m_insertIds.push_back(mysql_stmt_insert_id(stmt));
data->m_resultStatus = QUERY_SUCCESS;

if (mysql_stmt_result_metadata(stmt) == nullptr) {
MYSQL_RES* metaData = mysql_stmt_result_metadata(stmt);
if (metaData == nullptr) {
//This means the statement does not have a resultset (this apparently happens when calling stored procedures)
//We need to skip this result, otherwise it screws up the mysql connection
//Add an empty ResultData in that case
//This is only necessary due to MariaDB client behaving differently to the Mysql client
//otherwise we get a hang in the rest of the code below
data->m_results.emplace_back();
continue;
}
auto f = finally([&] { mysql_free_result(metaData); });
//There is a potential race condition here. What happens
//when the query executes fine but something goes wrong while storing the result?
mysqlStmtStoreResult(stmt);
data->m_results.emplace_back(stmt);
mysql_stmt_free_result(stmt);
auto f2 = finally([&] { mysql_stmt_free_result(stmt); });
data->m_results.emplace_back(stmt, metaData);
} while (mysqlStmtNextResult(stmt));
}
} catch (const MySQLException& error) {
Expand Down
7 changes: 2 additions & 5 deletions MySQLOO/source/ResultData.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ ResultData::ResultData(unsigned int columnCount, unsigned int rows) {
this->rows.reserve(rows);
}

ResultData::ResultData() : ResultData(0, 0) {}
ResultData::ResultData() : ResultData((unsigned int) 0, (unsigned int) 0) {} //Avoids conflict with pointers

//Stores all of the rows of a result set
//This is used so the result set can be free'd and doesn't have to be used in
Expand Down Expand Up @@ -54,11 +54,8 @@ static void mysqlStmtBindResult(MYSQL_STMT* stmt, MYSQL_BIND* bind) {

//Stores all of the rows of a prepared query
//This needs to be done because the query shouldn't be accessed from a different thread
ResultData::ResultData(MYSQL_STMT* result) : ResultData((unsigned int)mysql_stmt_field_count(result), (unsigned int)mysql_stmt_num_rows(result)) {
ResultData::ResultData(MYSQL_STMT* result, MYSQL_RES* metaData) : ResultData((unsigned int)mysql_stmt_field_count(result), (unsigned int)mysql_stmt_num_rows(result)) {
if (this->columnCount == 0) return;
MYSQL_RES * metaData = mysql_stmt_result_metadata(result);
if (metaData == nullptr) { throw MySQLException(0, "mysql_stmt_result_metadata: Unknown Error"); }
auto f = finally([&] { mysql_free_result(metaData); });
MYSQL_FIELD* fields = mysql_fetch_fields(metaData);
std::vector<MYSQL_BIND> binds(columnCount);
std::vector<std::vector<char>> buffers;
Expand Down

0 comments on commit 0d0191f

Please sign in to comment.