Blame SOURCES/0001-Memory-leak-in-SQLPrepare-with-queries-that-use-para.patch

cfa79d
From 4cf222c082950ff6a713792f68e2a2882135199e Mon Sep 17 00:00:00 2001
cfa79d
From: Bogdan Degtyariov <bogdan.degtyariov@oracle.com>
cfa79d
Date: Wed, 4 Sep 2013 16:46:27 +1000
cfa79d
Subject: [PATCH] Memory leak in SQLPrepare with queries that use parameters
cfa79d
 (Bug# 17400483/70113) - no test case
cfa79d
cfa79d
---
cfa79d
 ChangeLog                 |  2 ++
cfa79d
 driver/catalog_no_i_s.c   |  1 +
cfa79d
 driver/my_prepared_stmt.c | 21 ++++++++++++++-------
cfa79d
 driver/my_stmt.c          | 35 ++++++++++++++++++++++-------------
cfa79d
 4 files changed, 39 insertions(+), 20 deletions(-)
cfa79d
cfa79d
diff --git a/driver/catalog_no_i_s.c b/driver/catalog_no_i_s.c
cfa79d
index ac54d3e..be4d616 100644
cfa79d
--- a/driver/catalog_no_i_s.c
cfa79d
+++ b/driver/catalog_no_i_s.c
cfa79d
@@ -2141,6 +2141,7 @@ mysql_tables(SQLHSTMT hstmt,
cfa79d
       if (!row_count)
cfa79d
       {
cfa79d
         mysql_free_result(stmt->result);
cfa79d
+        stmt->result= NULL;
cfa79d
         goto empty_set;
cfa79d
       }
cfa79d
 
cfa79d
diff --git a/driver/my_prepared_stmt.c b/driver/my_prepared_stmt.c
cfa79d
index 71a5648..126d892 100644
cfa79d
--- a/driver/my_prepared_stmt.c
cfa79d
+++ b/driver/my_prepared_stmt.c
cfa79d
@@ -1,5 +1,5 @@
cfa79d
 /*
cfa79d
-  Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
cfa79d
+  Copyright (c) 2012-2013, Oracle and/or its affiliates. All rights reserved.
cfa79d
 
cfa79d
   The MySQL Connector/ODBC is licensed under the terms of the GPLv2
cfa79d
   <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
cfa79d
@@ -223,10 +223,17 @@ void free_result_bind(STMT *stmt)
cfa79d
 {
cfa79d
   if (stmt->result_bind != NULL)
cfa79d
   {
cfa79d
+    int i, field_cnt= field_count(stmt);
cfa79d
+
cfa79d
     x_free(stmt->result_bind[0].is_null);
cfa79d
     x_free(stmt->result_bind[0].length);
cfa79d
     x_free(stmt->result_bind[0].error);
cfa79d
-    x_free(stmt->result_bind[0].buffer);
cfa79d
+
cfa79d
+    /* buffer was allocated for each column */
cfa79d
+    for (i= 0; i < field_cnt; i++)
cfa79d
+    {
cfa79d
+      x_free(stmt->result_bind[i].buffer);
cfa79d
+    }
cfa79d
 
cfa79d
     x_free(stmt->result_bind);
cfa79d
     stmt->result_bind= 0;
cfa79d
@@ -438,11 +445,11 @@ int ssps_bind_result(STMT *stmt)
cfa79d
                                                       IS_PS_OUT_PARAMS(stmt));
cfa79d
 
cfa79d
       stmt->result_bind[i].buffer_type  = p.type;
cfa79d
-	  stmt->result_bind[i].buffer       = p.buffer;
cfa79d
-	  stmt->result_bind[i].buffer_length= (unsigned long)p.size;
cfa79d
-	  stmt->result_bind[i].length       = &len[i];
cfa79d
-	  stmt->result_bind[i].is_null      = &is_null[i];
cfa79d
-	  stmt->result_bind[i].error        = &err[i];
cfa79d
+	    stmt->result_bind[i].buffer       = p.buffer;
cfa79d
+	    stmt->result_bind[i].buffer_length= (unsigned long)p.size;
cfa79d
+	    stmt->result_bind[i].length       = &len[i];
cfa79d
+	    stmt->result_bind[i].is_null      = &is_null[i];
cfa79d
+	    stmt->result_bind[i].error        = &err[i];
cfa79d
       stmt->result_bind[i].is_unsigned  = (field->flags & UNSIGNED_FLAG)? 1: 0;
cfa79d
 
cfa79d
       stmt->array[i]= p.buffer;
cfa79d
diff --git a/driver/my_stmt.c b/driver/my_stmt.c
cfa79d
index 0dd059f..6e201d5 100644
cfa79d
--- a/driver/my_stmt.c
cfa79d
+++ b/driver/my_stmt.c
cfa79d
@@ -44,7 +44,16 @@ BOOL returned_result(STMT *stmt)
cfa79d
   if (ssps_used(stmt))
cfa79d
   {
cfa79d
     /* Basically at this point we are supposed to get result already */
cfa79d
-    return stmt->result ? TRUE : mysql_stmt_result_metadata(stmt->ssps) != NULL;
cfa79d
+    MYSQL_RES *temp_res= NULL;
cfa79d
+
cfa79d
+    if ((stmt->result != NULL) || 
cfa79d
+        (temp_res= mysql_stmt_result_metadata(stmt->ssps)) != NULL)
cfa79d
+    {
cfa79d
+      /* mysql_free_result checks for NULL, so we can always call it */
cfa79d
+      mysql_free_result(temp_res);
cfa79d
+      return TRUE;
cfa79d
+    }
cfa79d
+    return FALSE;
cfa79d
   }
cfa79d
   else
cfa79d
   {
cfa79d
@@ -55,24 +64,18 @@ BOOL returned_result(STMT *stmt)
cfa79d
 
cfa79d
 my_bool free_current_result(STMT *stmt)
cfa79d
 {
cfa79d
+  my_bool res= 0;
cfa79d
   if (returned_result(stmt))
cfa79d
   {
cfa79d
     if (ssps_used(stmt))
cfa79d
- 
cfa79d
-    {
cfa79d
-      my_bool res= mysql_stmt_free_result(stmt->ssps);
cfa79d
-      stmt->result= NULL;
cfa79d
-
cfa79d
-      return res;
cfa79d
-    }
cfa79d
-    else
cfa79d
     {
cfa79d
-      mysql_free_result(stmt->result);
cfa79d
-      stmt->result= NULL;
cfa79d
-      return '\0';
cfa79d
+      res= mysql_stmt_free_result(stmt->ssps);
cfa79d
     }
cfa79d
+    /* We need to always free stmt->result because SSPS keep metadata there */
cfa79d
+    mysql_free_result(stmt->result);
cfa79d
+    stmt->result= NULL;
cfa79d
   }
cfa79d
-  return '\0';
cfa79d
+  return res;
cfa79d
 }
cfa79d
 
cfa79d
 
cfa79d
@@ -98,6 +101,9 @@ MYSQL_RES * stmt_get_result(STMT *stmt, BOOL force_use)
cfa79d
    we need to use/store each resultset of multiple resultsets */
cfa79d
 MYSQL_RES * get_result_metadata(STMT *stmt, BOOL force_use)
cfa79d
 {
cfa79d
+  /* just a precaution, mysql_free_result checks for NULL anywat */
cfa79d
+  mysql_free_result(stmt->result);
cfa79d
+
cfa79d
   if (ssps_used(stmt))
cfa79d
   {
cfa79d
     stmt->result= mysql_stmt_result_metadata(stmt->ssps);
cfa79d
@@ -399,6 +405,9 @@ SQLRETURN prepare(STMT *stmt, char * query, SQLINTEGER query_length)
cfa79d
 
cfa79d
       stmt->param_count= mysql_stmt_param_count(stmt->ssps);
cfa79d
 
cfa79d
+      /* make sure we free the result from the previous time */
cfa79d
+      mysql_free_result(stmt->result);
cfa79d
+
cfa79d
       /* Getting result metadata */
cfa79d
       if ((stmt->result= mysql_stmt_result_metadata(stmt->ssps)))
cfa79d
       {
cfa79d
-- 
cfa79d
2.13.3
cfa79d