From bbc04974f1b38177ef4df15507c597ff0e1d6dbd Mon Sep 17 00:00:00 2001 From: Rene Cannao Date: Wed, 21 Jan 2026 23:58:44 +0000 Subject: [PATCH] fix: Fix mysql_query failure path and affected_rows race condition Fix two issues in Query_Tool_Handler's execute_query functions: 1. mysql_query() failure path now returns immediately after return_connection() instead of continuing to process on bad state. 2. Capture affected_rows BEFORE return_connection() to avoid race condition. Previously, mysql_affected_rows() was called after return_connection(), potentially accessing a stale connection. Apply fixes to both execute_query() and execute_query_with_schema(). Addresses coderabbitai review comments. --- lib/Query_Tool_Handler.cpp | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/lib/Query_Tool_Handler.cpp b/lib/Query_Tool_Handler.cpp index 5ff9868b9..8b7badaee 100644 --- a/lib/Query_Tool_Handler.cpp +++ b/lib/Query_Tool_Handler.cpp @@ -365,21 +365,28 @@ std::string Query_Tool_Handler::execute_query(const std::string& query) { return "{\"error\": \"No available connection\"}"; } - std::string result = "{\"error\": \"Query execution failed\"}"; + MYSQL* mysql_ptr = static_cast(mysql); - if (mysql_query(static_cast(mysql), query.c_str())) { - proxy_error("Query_Tool_Handler: Query failed: %s\n", mysql_error(static_cast(mysql))); + if (mysql_query(mysql_ptr, query.c_str())) { + proxy_error("Query_Tool_Handler: Query failed: %s\n", mysql_error(mysql_ptr)); return_connection(mysql); + json j; + j["success"] = false; + j["error"] = std::string(mysql_error(mysql_ptr)); + return j.dump(); } - MYSQL_RES* res = mysql_store_result(static_cast(mysql)); + MYSQL_RES* res = mysql_store_result(mysql_ptr); + + // Capture affected_rows BEFORE return_connection to avoid race condition + unsigned long affected_rows_val = mysql_affected_rows(mysql_ptr); return_connection(mysql); if (!res) { // No result set (e.g., INSERT/UPDATE) json j; j["success"] = true; - j["affected_rows"] = static_cast(mysql_affected_rows(static_cast(mysql))); + j["affected_rows"] = static_cast(affected_rows_val); return j.dump(); } @@ -444,13 +451,16 @@ std::string Query_Tool_Handler::execute_query_with_schema( } MYSQL_RES* res = mysql_store_result(mysql_ptr); + + // Capture affected_rows BEFORE return_connection to avoid race condition + unsigned long affected_rows_val = mysql_affected_rows(mysql_ptr); return_connection(mysql); if (!res) { // No result set (e.g., INSERT/UPDATE) json j; j["success"] = true; - j["affected_rows"] = static_cast(mysql_affected_rows(mysql_ptr)); + j["affected_rows"] = static_cast(affected_rows_val); return j.dump(); }