Details
-
Bug
-
Status: In Review (View Workflow)
-
Major
-
Resolution: Unresolved
-
13.1.1
-
None
Description
Description
When a statement run through mysql_real_connect_local() (the sql service used by plugins) fails after the result set metadata and some rows were produced, the half-built result set is never freed. The server then prints this at shutdown:
Warning: Internal memory accounting error of 8192 bytes
|
Cause
- Protocol_local::begin_dataset() (sql/sql_prepare.cc) allocates a MYSQL_DATA with its own MEM_ROOT. The MEM_ROOT has an 8192-byte first block and holds the field definitions and rows.
- If an error occurs mid-statement, net_send_error_packet() marks that same dataset with the error.
- mysql_store_result() then fails in loc_read_rows(), which calls embedded_get_error().
- embedded_get_error() frees the dataset with my_free(data) and never calls free_root(&data->alloc), so the MEM_ROOT blocks stay allocated.
- The blocks are not thread-specific, so they are counted in global_memory_used and still outstanding at shutdown, which gives the 8192-byte warning.
How to reproduce
install plugin test_sql_service soname 'test_sql_service'; |
CREATE TABLE t1 (id INT NOT NULL PRIMARY KEY) ENGINE=InnoDB; |
INSERT INTO t1 VALUES (1),(2),(3); |
CREATE FUNCTION f1(i INT) RETURNS INT |
BEGIN
|
IF i = 3 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT='row 3 fails'; END IF; |
RETURN i; |
END; |
set global test_sql_service_execute_sql_local= 'SELECT f1(id) FROM test.t1'; |
plugins.test_sql_service_error_in_resultset [ pass ] 46
|
***Warnings generated in error logs during shutdown after running tests: plugins.test_sql_service_error_in_resultset |
 |
Warning: Internal memory accounting error of 8192 bytes
|
Possible fix
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
|
index 19c608c3072..ebe01f0c8c5 100644
|
--- a/sql/sql_prepare.cc
|
+++ b/sql/sql_prepare.cc
|
@@ -6574,7 +6574,11 @@ static void embedded_get_error(MYSQL *mysql, MYSQL_DATA *data) |
strmake_buf(net->last_error, ei->info);
|
memcpy(net->sqlstate, ei->sqlstate, sizeof(net->sqlstate)); |
mysql->server_status= ei->server_status;
|
- my_free(data);
|
+ /* |
+ The dataset may have a MEM_ROOT with the fields and the rows sent before
|
+ the error, so free_root() it too, not only the dataset itself.
|
+ */
|
+ free_rows(data);
|
}
|
|
|