Commit 79e1fd8d authored by venu@myvenu.com's avatar venu@myvenu.com

Fix leak when the client disconnects with open prep statements

parent cb00984a
...@@ -5299,14 +5299,11 @@ static my_bool stmt_close(MYSQL_STMT *stmt, my_bool skip_list) ...@@ -5299,14 +5299,11 @@ static my_bool stmt_close(MYSQL_STMT *stmt, my_bool skip_list)
int4store(buff, stmt->stmt_id); int4store(buff, stmt->stmt_id);
error= simple_command(stmt->mysql, COM_CLOSE_STMT, buff, 4, 1); error= simple_command(stmt->mysql, COM_CLOSE_STMT, buff, 4, 1);
} }
if (!error)
{
mysql_free_result(stmt->result); mysql_free_result(stmt->result);
free_root(&stmt->mem_root, MYF(0)); free_root(&stmt->mem_root, MYF(0));
if (!skip_list) if (!skip_list)
stmt->mysql->stmts= list_delete(stmt->mysql->stmts, &stmt->list); stmt->mysql->stmts= list_delete(stmt->mysql->stmts, &stmt->list);
my_free((gptr) stmt, MYF(MY_WME)); my_free((gptr) stmt, MYF(MY_WME));
}
DBUG_RETURN(error); DBUG_RETURN(error);
} }
......
...@@ -129,6 +129,7 @@ int compare_prep_stmt(void *not_used, PREP_STMT *stmt, ulong *key) ...@@ -129,6 +129,7 @@ int compare_prep_stmt(void *not_used, PREP_STMT *stmt, ulong *key)
void free_prep_stmt(PREP_STMT *stmt, TREE_FREE mode, void *not_used) void free_prep_stmt(PREP_STMT *stmt, TREE_FREE mode, void *not_used)
{ {
my_free((char *)stmt->param, MYF(MY_ALLOW_ZERO_PTR));
free_items(stmt->free_list); free_items(stmt->free_list);
free_root(&stmt->mem_root, MYF(0)); free_root(&stmt->mem_root, MYF(0));
} }
...@@ -319,7 +320,7 @@ static void setup_param_date(Item_param *param, uchar **pos) ...@@ -319,7 +320,7 @@ static void setup_param_date(Item_param *param, uchar **pos)
uchar *to= *pos; uchar *to= *pos;
TIME tm; TIME tm;
tm.year = (uint) sint2korr(to); tm.year= (uint) sint2korr(to);
tm.month= (uint) to[2]; tm.month= (uint) to[2];
tm.day= (uint) to[3]; tm.day= (uint) to[3];
...@@ -344,44 +345,44 @@ static void setup_param_functions(Item_param *param, uchar param_type) ...@@ -344,44 +345,44 @@ static void setup_param_functions(Item_param *param, uchar param_type)
switch (param_type) { switch (param_type) {
case FIELD_TYPE_TINY: case FIELD_TYPE_TINY:
param->setup_param_func= setup_param_tiny; param->setup_param_func= setup_param_tiny;
param->item_result_type = INT_RESULT; param->item_result_type= INT_RESULT;
break; break;
case FIELD_TYPE_SHORT: case FIELD_TYPE_SHORT:
param->setup_param_func= setup_param_short; param->setup_param_func= setup_param_short;
param->item_result_type = INT_RESULT; param->item_result_type= INT_RESULT;
break; break;
case FIELD_TYPE_LONG: case FIELD_TYPE_LONG:
param->setup_param_func= setup_param_int32; param->setup_param_func= setup_param_int32;
param->item_result_type = INT_RESULT; param->item_result_type= INT_RESULT;
break; break;
case FIELD_TYPE_LONGLONG: case FIELD_TYPE_LONGLONG:
param->setup_param_func= setup_param_int64; param->setup_param_func= setup_param_int64;
param->item_result_type = INT_RESULT; param->item_result_type= INT_RESULT;
break; break;
case FIELD_TYPE_FLOAT: case FIELD_TYPE_FLOAT:
param->setup_param_func= setup_param_float; param->setup_param_func= setup_param_float;
param->item_result_type = REAL_RESULT; param->item_result_type= REAL_RESULT;
break; break;
case FIELD_TYPE_DOUBLE: case FIELD_TYPE_DOUBLE:
param->setup_param_func= setup_param_double; param->setup_param_func= setup_param_double;
param->item_result_type = REAL_RESULT; param->item_result_type= REAL_RESULT;
break; break;
case FIELD_TYPE_TIME: case FIELD_TYPE_TIME:
param->setup_param_func= setup_param_time; param->setup_param_func= setup_param_time;
param->item_result_type = STRING_RESULT; param->item_result_type= STRING_RESULT;
break; break;
case FIELD_TYPE_DATE: case FIELD_TYPE_DATE:
param->setup_param_func= setup_param_date; param->setup_param_func= setup_param_date;
param->item_result_type = STRING_RESULT; param->item_result_type= STRING_RESULT;
break; break;
case FIELD_TYPE_DATETIME: case FIELD_TYPE_DATETIME:
case FIELD_TYPE_TIMESTAMP: case FIELD_TYPE_TIMESTAMP:
param->setup_param_func= setup_param_datetime; param->setup_param_func= setup_param_datetime;
param->item_result_type = STRING_RESULT; param->item_result_type= STRING_RESULT;
break; break;
default: default:
param->setup_param_func= setup_param_str; param->setup_param_func= setup_param_str;
param->item_result_type = STRING_RESULT; param->item_result_type= STRING_RESULT;
} }
} }
...@@ -453,7 +454,7 @@ static bool mysql_test_insert_fields(PREP_STMT *stmt, ...@@ -453,7 +454,7 @@ static bool mysql_test_insert_fields(PREP_STMT *stmt,
List_item *values; List_item *values;
DBUG_ENTER("mysql_test_insert_fields"); DBUG_ENTER("mysql_test_insert_fields");
if (!(table = open_ltable(thd,table_list,table_list->lock_type))) if (!(table= open_ltable(thd,table_list,table_list->lock_type)))
DBUG_RETURN(1); DBUG_RETURN(1);
if ((values= its++)) if ((values= its++))
...@@ -587,7 +588,7 @@ static bool send_prepare_results(PREP_STMT *stmt) ...@@ -587,7 +588,7 @@ static bool send_prepare_results(PREP_STMT *stmt)
{ {
THD *thd= stmt->thd; THD *thd= stmt->thd;
LEX *lex= &thd->lex; LEX *lex= &thd->lex;
enum enum_sql_command sql_command = thd->lex.sql_command; enum enum_sql_command sql_command= thd->lex.sql_command;
DBUG_ENTER("send_prepare_results"); DBUG_ENTER("send_prepare_results");
DBUG_PRINT("enter",("command: %d, param_count: %ld", DBUG_PRINT("enter",("command: %d, param_count: %ld",
sql_command, lex->param_count)); sql_command, lex->param_count));
...@@ -597,7 +598,7 @@ static bool send_prepare_results(PREP_STMT *stmt) ...@@ -597,7 +598,7 @@ static bool send_prepare_results(PREP_STMT *stmt)
stmt->free_list= thd->free_list; // Save items used in stmt stmt->free_list= thd->free_list; // Save items used in stmt
thd->free_list= 0; thd->free_list= 0;
SELECT_LEX *select_lex = &lex->select_lex; SELECT_LEX *select_lex= &lex->select_lex;
TABLE_LIST *tables=(TABLE_LIST*) select_lex->table_list.first; TABLE_LIST *tables=(TABLE_LIST*) select_lex->table_list.first;
switch (sql_command) { switch (sql_command) {
...@@ -683,12 +684,17 @@ static bool init_param_items(PREP_STMT *stmt) ...@@ -683,12 +684,17 @@ static bool init_param_items(PREP_STMT *stmt)
List<Item> &params= stmt->thd->lex.param_list; List<Item> &params= stmt->thd->lex.param_list;
Item_param **to; Item_param **to;
if (!stmt->param_count)
stmt->param= (Item_param **)0;
else
{
if (!(stmt->param= to= (Item_param **) if (!(stmt->param= to= (Item_param **)
my_malloc(sizeof(Item_param *)*(stmt->param_count+1), my_malloc(sizeof(Item_param *)*(stmt->param_count+1),
MYF(MY_WME)))) MYF(MY_WME))))
return 1; return 1;
List_iterator<Item> param_iterator(params); List_iterator<Item> param_iterator(params);
while ((*(to++) = (Item_param *)param_iterator++)); while ((*(to++)= (Item_param *)param_iterator++));
}
return 0; return 0;
} }
...@@ -726,7 +732,7 @@ static void init_stmt_execute(PREP_STMT *stmt) ...@@ -726,7 +732,7 @@ static void init_stmt_execute(PREP_STMT *stmt)
bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length) bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length)
{ {
MEM_ROOT thd_root = thd->mem_root; MEM_ROOT thd_root= thd->mem_root;
PREP_STMT stmt; PREP_STMT stmt;
DBUG_ENTER("mysql_stmt_prepare"); DBUG_ENTER("mysql_stmt_prepare");
...@@ -758,7 +764,7 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length) ...@@ -758,7 +764,7 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length)
err: err:
stmt.mem_root= stmt.thd->mem_root; stmt.mem_root= stmt.thd->mem_root;
free_prep_stmt(&stmt, free_free, (void*) 0); free_prep_stmt(&stmt, free_free, (void*) 0);
thd->mem_root = thd_root; // restore main mem_root thd->mem_root= thd_root; // restore main mem_root
DBUG_RETURN(1); DBUG_RETURN(1);
} }
...@@ -878,9 +884,8 @@ void mysql_stmt_free(THD *thd, char *packet) ...@@ -878,9 +884,8 @@ void mysql_stmt_free(THD *thd, char *packet)
send_error(thd); // Not seen by the client send_error(thd); // Not seen by the client
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
my_free((char *)stmt->param, MYF(MY_ALLOW_ZERO_PTR)); tree_delete(&thd->prepared_statements, (void*) &stmt_id, (void *)0);
tree_delete(&thd->prepared_statements, (void*) &stmt, (void *)0); thd->last_prepared_stmt= (PREP_STMT *)0;
thd->last_prepared_stmt=0;
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
......
...@@ -284,6 +284,7 @@ static void my_print_result_metadata(MYSQL_RES *result) ...@@ -284,6 +284,7 @@ static void my_print_result_metadata(MYSQL_RES *result)
mysql_field_seek(result,0); mysql_field_seek(result,0);
fputc('\n', stdout); fputc('\n', stdout);
fputc('\n', stdout);
field_count = mysql_num_fields(result); field_count = mysql_num_fields(result);
for(i=0; i< field_count; i++) for(i=0; i< field_count; i++)
...@@ -702,6 +703,7 @@ static void test_tran_bdb() ...@@ -702,6 +703,7 @@ static void test_tran_bdb()
mytest(result); mytest(result);
my_process_result_set(result); my_process_result_set(result);
mysql_free_result(result);
/* test the results now, only one row should exists */ /* test the results now, only one row should exists */
rc = mysql_query(mysql,"SELECT * FROM my_demo_transaction"); rc = mysql_query(mysql,"SELECT * FROM my_demo_transaction");
...@@ -779,6 +781,7 @@ static void test_tran_innodb() ...@@ -779,6 +781,7 @@ static void test_tran_innodb()
mytest(result); mytest(result);
my_process_result_set(result); my_process_result_set(result);
mysql_free_result(result);
/* test the results now, only one row should exists */ /* test the results now, only one row should exists */
rc = mysql_query(mysql,"SELECT * FROM my_demo_transaction"); rc = mysql_query(mysql,"SELECT * FROM my_demo_transaction");
...@@ -930,6 +933,7 @@ static void test_prepare_field_result() ...@@ -930,6 +933,7 @@ static void test_prepare_field_result()
param_count= mysql_num_fields(result); param_count= mysql_num_fields(result);
fprintf(stdout,"\n\n total fields: `%d` (expected: `5`)", param_count); fprintf(stdout,"\n\n total fields: `%d` (expected: `5`)", param_count);
myassert(param_count == 5); myassert(param_count == 5);
mysql_free_result(result);
mysql_stmt_close(stmt); mysql_stmt_close(stmt);
} }
...@@ -1478,7 +1482,7 @@ static void test_select_direct() ...@@ -1478,7 +1482,7 @@ static void test_select_direct()
*********************************************************/ *********************************************************/
static void test_select_prepare() static void test_select_prepare()
{ {
int rc, count; int rc;
MYSQL_STMT *stmt; MYSQL_STMT *stmt;
myheader("test_select_prepare"); myheader("test_select_prepare");
...@@ -1511,7 +1515,8 @@ static void test_select_prepare() ...@@ -1511,7 +1515,8 @@ static void test_select_prepare()
rc = mysql_execute(stmt); rc = mysql_execute(stmt);
mystmt(stmt,rc); mystmt(stmt,rc);
count= my_process_stmt_result(stmt); myassert(1 == my_process_stmt_result(stmt));
mysql_stmt_close(stmt);
rc = mysql_query(mysql,"DROP TABLE test_select"); rc = mysql_query(mysql,"DROP TABLE test_select");
myquery(rc); myquery(rc);
...@@ -1540,8 +1545,7 @@ static void test_select_prepare() ...@@ -1540,8 +1545,7 @@ static void test_select_prepare()
rc = mysql_execute(stmt); rc = mysql_execute(stmt);
mystmt(stmt,rc); mystmt(stmt,rc);
my_process_stmt_result(stmt); myassert(1 == my_process_stmt_result(stmt));
mysql_stmt_close(stmt); mysql_stmt_close(stmt);
} }
...@@ -1615,7 +1619,7 @@ static void test_select() ...@@ -1615,7 +1619,7 @@ static void test_select()
rc = mysql_execute(stmt); rc = mysql_execute(stmt);
mystmt(stmt, rc); mystmt(stmt, rc);
myassert(my_process_stmt_result(stmt) != 0); myassert(my_process_stmt_result(stmt) == 1);
mysql_stmt_close(stmt); mysql_stmt_close(stmt);
} }
...@@ -1817,6 +1821,7 @@ static void test_long_data() ...@@ -1817,6 +1821,7 @@ static void test_long_data()
verify_col_data("test_long_data","col1","999"); verify_col_data("test_long_data","col1","999");
verify_col_data("test_long_data","col2","Michael 'Monty' Widenius"); verify_col_data("test_long_data","col2","Michael 'Monty' Widenius");
verify_col_data("test_long_data","col3","Venu"); verify_col_data("test_long_data","col3","Venu");
mysql_stmt_close(stmt);
} }
...@@ -3608,8 +3613,9 @@ static void test_stmt_close() ...@@ -3608,8 +3613,9 @@ static void test_stmt_close()
fprintf(stdout,"\n mysql_close_stmt(1) returned: %d", rc); fprintf(stdout,"\n mysql_close_stmt(1) returned: %d", rc);
myassert(rc == 0); myassert(rc == 0);
mysql_close(lmysql); /* it should free all open stmts(stmt3, stmt2) */ mysql_close(lmysql); /* it should free all open stmts(stmt3, 2 and 1) */
#if NOT_VALID
rc= mysql_stmt_close(stmt3); rc= mysql_stmt_close(stmt3);
fprintf(stdout,"\n mysql_close_stmt(3) returned: %d", rc); fprintf(stdout,"\n mysql_close_stmt(3) returned: %d", rc);
myassert( rc == 1); myassert( rc == 1);
...@@ -3617,6 +3623,7 @@ static void test_stmt_close() ...@@ -3617,6 +3623,7 @@ static void test_stmt_close()
rc= mysql_stmt_close(stmt2); rc= mysql_stmt_close(stmt2);
fprintf(stdout,"\n mysql_close_stmt(2) returned: %d", rc); fprintf(stdout,"\n mysql_close_stmt(2) returned: %d", rc);
myassert( rc == 1); myassert( rc == 1);
#endif
count= 100; count= 100;
bind[0].buffer=(char *)&count; bind[0].buffer=(char *)&count;
...@@ -3625,6 +3632,7 @@ static void test_stmt_close() ...@@ -3625,6 +3632,7 @@ static void test_stmt_close()
rc = mysql_bind_param(stmt_x, bind); rc = mysql_bind_param(stmt_x, bind);
mystmt(stmt_x, rc); mystmt(stmt_x, rc);
rc = mysql_execute(stmt_x); rc = mysql_execute(stmt_x);
mystmt(stmt_x, rc); mystmt(stmt_x, rc);
...@@ -3673,7 +3681,6 @@ static void test_set_variable() ...@@ -3673,7 +3681,6 @@ static void test_set_variable()
result= mysql_param_result(stmt); result= mysql_param_result(stmt);
mytest_r(result); mytest_r(result);
bind[0].buffer_type= MYSQL_TYPE_LONG; bind[0].buffer_type= MYSQL_TYPE_LONG;
bind[0].buffer=(char *)&select_limit; bind[0].buffer=(char *)&select_limit;
bind[0].is_null=0; bind[0].is_null=0;
...@@ -3745,6 +3752,8 @@ static void test_insert_meta() ...@@ -3745,6 +3752,8 @@ static void test_insert_meta()
result= mysql_param_result(stmt); result= mysql_param_result(stmt);
mytest_r(result); mytest_r(result);
mysql_stmt_close(stmt);
strmov(query,"INSERT INTO test_prep_insert VALUES(?,'venu',?)"); strmov(query,"INSERT INTO test_prep_insert VALUES(?,'venu',?)");
stmt = mysql_prepare(mysql, query, strlen(query)); stmt = mysql_prepare(mysql, query, strlen(query));
mystmt_init(stmt); mystmt_init(stmt);
...@@ -3807,6 +3816,8 @@ static void test_update_meta() ...@@ -3807,6 +3816,8 @@ static void test_update_meta()
result= mysql_param_result(stmt); result= mysql_param_result(stmt);
mytest_r(result); mytest_r(result);
mysql_stmt_close(stmt);
strmov(query,"UPDATE test_prep_update SET col1=?, col2='venu' WHERE col3=?"); strmov(query,"UPDATE test_prep_update SET col1=?, col2='venu' WHERE col3=?");
stmt = mysql_prepare(mysql, query, strlen(query)); stmt = mysql_prepare(mysql, query, strlen(query));
mystmt_init(stmt); mystmt_init(stmt);
...@@ -3901,7 +3912,7 @@ static void test_select_meta() ...@@ -3901,7 +3912,7 @@ static void test_select_meta()
field= mysql_fetch_field(result); field= mysql_fetch_field(result);
mytest_r(field); mytest_r(field);
n
mysql_free_result(result); mysql_free_result(result);
mysql_stmt_close(stmt); mysql_stmt_close(stmt);
} }
...@@ -4023,7 +4034,6 @@ static void test_multi_stmt() ...@@ -4023,7 +4034,6 @@ static void test_multi_stmt()
bind[1].length = &length[1]; bind[1].length = &length[1];
bind[1].is_null= &is_null[0]; bind[1].is_null= &is_null[0];
rc = mysql_bind_param(stmt, bind); rc = mysql_bind_param(stmt, bind);
mystmt(stmt, rc); mystmt(stmt, rc);
...@@ -4626,7 +4636,6 @@ static void test_store_result2() ...@@ -4626,7 +4636,6 @@ static void test_store_result2()
rc = mysql_fetch(stmt); rc = mysql_fetch(stmt);
myassert(rc == MYSQL_NO_DATA); myassert(rc == MYSQL_NO_DATA);
mysql_stmt_close(stmt); mysql_stmt_close(stmt);
} }
...@@ -5239,13 +5248,17 @@ int main(int argc, char **argv) ...@@ -5239,13 +5248,17 @@ int main(int argc, char **argv)
{ {
MY_INIT(argv[0]); MY_INIT(argv[0]);
get_options(argc,argv); get_options(argc,argv);
time_t start_time, end_time;
double total_time= 0;
client_connect(); /* connect to server */ client_connect(); /* connect to server */
for (iter_count=1; iter_count <= opt_count; iter_count++) for (iter_count=1; iter_count <= opt_count; iter_count++)
{ {
/* Start of tests */ /* Start of tests */
test_count= 0; test_count= 1;
start_time= time((time_t *)0);
test_fetch_null(); /* to fetch null data */ test_fetch_null(); /* to fetch null data */
test_fetch_date(); /* to fetch date,time and timestamp */ test_fetch_date(); /* to fetch date,time and timestamp */
...@@ -5319,14 +5332,20 @@ int main(int argc, char **argv) ...@@ -5319,14 +5332,20 @@ int main(int argc, char **argv)
test_manual_sample(); /* sample in the manual */ test_manual_sample(); /* sample in the manual */
test_pure_coverage(); /* keep pure coverage happy */ test_pure_coverage(); /* keep pure coverage happy */
test_buffers(); /* misc buffer handling */ test_buffers(); /* misc buffer handling */
end_time= time((time_t *)0);
total_time+= difftime(end_time, start_time);
/* End of tests */ /* End of tests */
} }
client_disconnect(); /* disconnect from server */ client_disconnect(); /* disconnect from server */
fprintf(stdout,"\n\nAll '%d' tests were successful (in '%d' iterations)", fprintf(stdout,"\n\nAll '%d' tests were successful (in '%d' iterations)",
test_count-1, opt_count); test_count-1, opt_count);
fprintf(stdout,"\n Total execution time: %g SECS", total_time);
if (opt_count > 1)
fprintf(stdout," (Avg: %g SECS)", total_time/opt_count);
fprintf(stdout,"\nSUCCESS !!!\n"); fprintf(stdout,"\n\nSUCCESS !!!\n");
return(0); return(0);
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment