Bug#15518 Reusing a stmt that has failed during prepare does not clear error
- Always reset error when calling mysql_stmt_prepare a second time - Set stmt->state to MYSQL_STMT_INIT_DONE before closing prepared stmt in server. - Add test to mysql_client_test - Remove mysql_stmt_close in mysqltest after each query - Close all open statements in mysqltest if disable_ps_protocol is called.
This commit is contained in:
parent
b1664c220c
commit
f507bb2cb3
@ -719,6 +719,20 @@ void close_connections()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void close_statements()
|
||||||
|
{
|
||||||
|
struct st_connection *con;
|
||||||
|
DBUG_ENTER("close_statements");
|
||||||
|
for (con= connections; con < next_con; con++)
|
||||||
|
{
|
||||||
|
if (con->stmt)
|
||||||
|
mysql_stmt_close(con->stmt);
|
||||||
|
con->stmt= 0;
|
||||||
|
}
|
||||||
|
DBUG_VOID_RETURN;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void close_files()
|
void close_files()
|
||||||
{
|
{
|
||||||
DBUG_ENTER("close_files");
|
DBUG_ENTER("close_files");
|
||||||
@ -2855,6 +2869,10 @@ void do_close_connection(struct st_command *command)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
if (next_con->stmt)
|
||||||
|
mysql_stmt_close(next_con->stmt);
|
||||||
|
next_con->stmt= 0;
|
||||||
|
|
||||||
mysql_close(&con->mysql);
|
mysql_close(&con->mysql);
|
||||||
if (con->util_mysql)
|
if (con->util_mysql)
|
||||||
mysql_close(con->util_mysql);
|
mysql_close(con->util_mysql);
|
||||||
@ -5050,10 +5068,7 @@ end:
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
var_set_errno(mysql_stmt_errno(stmt));
|
var_set_errno(mysql_stmt_errno(stmt));
|
||||||
#ifndef BUG15518_FIXED
|
|
||||||
mysql_stmt_close(stmt);
|
|
||||||
cur_con->stmt= NULL;
|
|
||||||
#endif
|
|
||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5838,6 +5853,8 @@ int main(int argc, char **argv)
|
|||||||
break;
|
break;
|
||||||
case Q_DISABLE_PS_PROTOCOL:
|
case Q_DISABLE_PS_PROTOCOL:
|
||||||
ps_protocol_enabled= 0;
|
ps_protocol_enabled= 0;
|
||||||
|
/* Close any open statements */
|
||||||
|
close_statements();
|
||||||
break;
|
break;
|
||||||
case Q_ENABLE_PS_PROTOCOL:
|
case Q_ENABLE_PS_PROTOCOL:
|
||||||
ps_protocol_enabled= ps_protocol;
|
ps_protocol_enabled= ps_protocol;
|
||||||
|
@ -2038,6 +2038,13 @@ mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, ulong length)
|
|||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Reset the last error in any case: that would clear the statement
|
||||||
|
if the previous prepare failed.
|
||||||
|
*/
|
||||||
|
stmt->last_errno= 0;
|
||||||
|
stmt->last_error[0]= '\0';
|
||||||
|
|
||||||
if ((int) stmt->state > (int) MYSQL_STMT_INIT_DONE)
|
if ((int) stmt->state > (int) MYSQL_STMT_INIT_DONE)
|
||||||
{
|
{
|
||||||
/* This is second prepare with another statement */
|
/* This is second prepare with another statement */
|
||||||
@ -2051,23 +2058,24 @@ mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, ulong length)
|
|||||||
*/
|
*/
|
||||||
stmt->bind_param_done= stmt->bind_result_done= FALSE;
|
stmt->bind_param_done= stmt->bind_result_done= FALSE;
|
||||||
stmt->param_count= stmt->field_count= 0;
|
stmt->param_count= stmt->field_count= 0;
|
||||||
stmt->last_errno= 0;
|
|
||||||
stmt->last_error[0]= '\0';
|
|
||||||
free_root(&stmt->mem_root, MYF(MY_KEEP_PREALLOC));
|
free_root(&stmt->mem_root, MYF(MY_KEEP_PREALLOC));
|
||||||
|
|
||||||
int4store(buff, stmt->stmt_id);
|
int4store(buff, stmt->stmt_id);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Close statement in server
|
||||||
|
|
||||||
If there was a 'use' result from another statement, or from
|
If there was a 'use' result from another statement, or from
|
||||||
mysql_use_result it won't be freed in mysql_stmt_free_result and
|
mysql_use_result it won't be freed in mysql_stmt_free_result and
|
||||||
we should get 'Commands out of sync' here.
|
we should get 'Commands out of sync' here.
|
||||||
*/
|
*/
|
||||||
|
stmt->state= MYSQL_STMT_INIT_DONE;
|
||||||
if (stmt_command(mysql, COM_STMT_CLOSE, buff, 4, stmt))
|
if (stmt_command(mysql, COM_STMT_CLOSE, buff, 4, stmt))
|
||||||
{
|
{
|
||||||
set_stmt_errmsg(stmt, mysql->net.last_error, mysql->net.last_errno,
|
set_stmt_errmsg(stmt, mysql->net.last_error, mysql->net.last_errno,
|
||||||
mysql->net.sqlstate);
|
mysql->net.sqlstate);
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
}
|
}
|
||||||
stmt->state= MYSQL_STMT_INIT_DONE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stmt_command(mysql, COM_STMT_PREPARE, query, length, stmt))
|
if (stmt_command(mysql, COM_STMT_PREPARE, query, length, stmt))
|
||||||
|
@ -11014,7 +11014,7 @@ static void test_view()
|
|||||||
rc= mysql_stmt_execute(stmt);
|
rc= mysql_stmt_execute(stmt);
|
||||||
check_execute(stmt, rc);
|
check_execute(stmt, rc);
|
||||||
rc= my_process_stmt_result(stmt);
|
rc= my_process_stmt_result(stmt);
|
||||||
assert(1 == rc);
|
DIE_UNLESS(1 == rc);
|
||||||
}
|
}
|
||||||
mysql_stmt_close(stmt);
|
mysql_stmt_close(stmt);
|
||||||
|
|
||||||
@ -11057,7 +11057,7 @@ static void test_view_where()
|
|||||||
rc= mysql_stmt_execute(stmt);
|
rc= mysql_stmt_execute(stmt);
|
||||||
check_execute(stmt, rc);
|
check_execute(stmt, rc);
|
||||||
rc= my_process_stmt_result(stmt);
|
rc= my_process_stmt_result(stmt);
|
||||||
assert(4 == rc);
|
DIE_UNLESS(4 == rc);
|
||||||
}
|
}
|
||||||
mysql_stmt_close(stmt);
|
mysql_stmt_close(stmt);
|
||||||
|
|
||||||
@ -11140,7 +11140,7 @@ static void test_view_2where()
|
|||||||
rc= mysql_stmt_execute(stmt);
|
rc= mysql_stmt_execute(stmt);
|
||||||
check_execute(stmt, rc);
|
check_execute(stmt, rc);
|
||||||
rc= my_process_stmt_result(stmt);
|
rc= my_process_stmt_result(stmt);
|
||||||
assert(0 == rc);
|
DIE_UNLESS(0 == rc);
|
||||||
|
|
||||||
mysql_stmt_close(stmt);
|
mysql_stmt_close(stmt);
|
||||||
|
|
||||||
@ -11193,7 +11193,7 @@ static void test_view_star()
|
|||||||
rc= mysql_stmt_execute(stmt);
|
rc= mysql_stmt_execute(stmt);
|
||||||
check_execute(stmt, rc);
|
check_execute(stmt, rc);
|
||||||
rc= my_process_stmt_result(stmt);
|
rc= my_process_stmt_result(stmt);
|
||||||
assert(0 == rc);
|
DIE_UNLESS(0 == rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
mysql_stmt_close(stmt);
|
mysql_stmt_close(stmt);
|
||||||
@ -11256,7 +11256,7 @@ static void test_view_insert()
|
|||||||
rc= mysql_stmt_execute(select_stmt);
|
rc= mysql_stmt_execute(select_stmt);
|
||||||
check_execute(select_stmt, rc);
|
check_execute(select_stmt, rc);
|
||||||
rowcount= (int)my_process_stmt_result(select_stmt);
|
rowcount= (int)my_process_stmt_result(select_stmt);
|
||||||
assert((i+1) == rowcount);
|
DIE_UNLESS((i+1) == rowcount);
|
||||||
}
|
}
|
||||||
mysql_stmt_close(insert_stmt);
|
mysql_stmt_close(insert_stmt);
|
||||||
mysql_stmt_close(select_stmt);
|
mysql_stmt_close(select_stmt);
|
||||||
@ -11297,7 +11297,7 @@ static void test_left_join_view()
|
|||||||
rc= mysql_stmt_execute(stmt);
|
rc= mysql_stmt_execute(stmt);
|
||||||
check_execute(stmt, rc);
|
check_execute(stmt, rc);
|
||||||
rc= my_process_stmt_result(stmt);
|
rc= my_process_stmt_result(stmt);
|
||||||
assert(3 == rc);
|
DIE_UNLESS(3 == rc);
|
||||||
}
|
}
|
||||||
mysql_stmt_close(stmt);
|
mysql_stmt_close(stmt);
|
||||||
|
|
||||||
@ -11373,7 +11373,7 @@ static void test_view_insert_fields()
|
|||||||
rc= mysql_stmt_execute(stmt);
|
rc= mysql_stmt_execute(stmt);
|
||||||
check_execute(stmt, rc);
|
check_execute(stmt, rc);
|
||||||
rc= my_process_stmt_result(stmt);
|
rc= my_process_stmt_result(stmt);
|
||||||
assert(1 == rc);
|
DIE_UNLESS(1 == rc);
|
||||||
|
|
||||||
mysql_stmt_close(stmt);
|
mysql_stmt_close(stmt);
|
||||||
rc= mysql_query(mysql, "DROP VIEW v1");
|
rc= mysql_query(mysql, "DROP VIEW v1");
|
||||||
@ -12851,6 +12851,82 @@ static void test_bug7990()
|
|||||||
DIE_UNLESS(!mysql_errno(mysql));
|
DIE_UNLESS(!mysql_errno(mysql));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Bug #15518 - Reusing a stmt that has failed during prepare
|
||||||
|
does not clear error
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void test_bug15518()
|
||||||
|
{
|
||||||
|
MYSQL_STMT *stmt;
|
||||||
|
MYSQL* mysql1;
|
||||||
|
int rc;
|
||||||
|
myheader("test_bug15518");
|
||||||
|
|
||||||
|
mysql1= mysql_init(NULL);
|
||||||
|
|
||||||
|
if (!mysql_real_connect(mysql1, opt_host, opt_user, opt_password,
|
||||||
|
opt_db ? opt_db : "test", opt_port, opt_unix_socket,
|
||||||
|
CLIENT_MULTI_STATEMENTS))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Failed to connect to the database\n");
|
||||||
|
DIE_UNLESS(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
stmt= mysql_stmt_init(mysql1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
The prepare of foo should fail with errno 1064 since
|
||||||
|
it's not a valid query
|
||||||
|
*/
|
||||||
|
rc= mysql_stmt_prepare(stmt, "foo", 3);
|
||||||
|
if (!opt_silent)
|
||||||
|
fprintf(stdout, "rc: %d, mysql_stmt_errno: %d, mysql_errno: %d\n",
|
||||||
|
rc, mysql_stmt_errno(stmt), mysql_errno(mysql1));
|
||||||
|
DIE_UNLESS(rc && mysql_stmt_errno(stmt) && mysql_errno(mysql1));
|
||||||
|
|
||||||
|
/*
|
||||||
|
Use the same stmt and reprepare with another query that
|
||||||
|
suceeds
|
||||||
|
*/
|
||||||
|
rc= mysql_stmt_prepare(stmt, "SHOW STATUS", 12);
|
||||||
|
if (!opt_silent)
|
||||||
|
fprintf(stdout, "rc: %d, mysql_stmt_errno: %d, mysql_errno: %d\n",
|
||||||
|
rc, mysql_stmt_errno(stmt), mysql_errno(mysql1));
|
||||||
|
DIE_UNLESS(!rc || mysql_stmt_errno(stmt) || mysql_errno(mysql1));
|
||||||
|
|
||||||
|
mysql_stmt_close(stmt);
|
||||||
|
DIE_UNLESS(!mysql_errno(mysql1));
|
||||||
|
|
||||||
|
/*
|
||||||
|
part2, when connection to server has been closed
|
||||||
|
after first prepare
|
||||||
|
*/
|
||||||
|
stmt= mysql_stmt_init(mysql1);
|
||||||
|
rc= mysql_stmt_prepare(stmt, "foo", 3);
|
||||||
|
if (!opt_silent)
|
||||||
|
fprintf(stdout, "rc: %d, mysql_stmt_errno: %d, mysql_errno: %d\n",
|
||||||
|
rc, mysql_stmt_errno(stmt), mysql_errno(mysql1));
|
||||||
|
DIE_UNLESS(rc && mysql_stmt_errno(stmt) && mysql_errno(mysql1));
|
||||||
|
|
||||||
|
/* Close connection to server */
|
||||||
|
mysql_close(mysql1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Use the same stmt and reprepare with another query that
|
||||||
|
suceeds. The prepare should fail with error 2013 since
|
||||||
|
connection to server has been closed.
|
||||||
|
*/
|
||||||
|
rc= mysql_stmt_prepare(stmt, "SHOW STATUS", 12);
|
||||||
|
if (!opt_silent)
|
||||||
|
fprintf(stdout, "rc: %d, mysql_stmt_errno: %d\n",
|
||||||
|
rc, mysql_stmt_errno(stmt));
|
||||||
|
DIE_UNLESS(rc && mysql_stmt_errno(stmt));
|
||||||
|
|
||||||
|
mysql_stmt_close(stmt);
|
||||||
|
DIE_UNLESS(mysql_errno(mysql1));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void test_view_sp_list_fields()
|
static void test_view_sp_list_fields()
|
||||||
{
|
{
|
||||||
@ -15009,7 +15085,7 @@ static void test_bug17667()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
assert(0==1);
|
DIE_UNLESS(0==1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -15588,6 +15664,7 @@ static struct my_tests_st my_tests[]= {
|
|||||||
{ "test_bug15752", test_bug15752 },
|
{ "test_bug15752", test_bug15752 },
|
||||||
{ "test_bug21206", test_bug21206 },
|
{ "test_bug21206", test_bug21206 },
|
||||||
{ "test_bug21726", test_bug21726 },
|
{ "test_bug21726", test_bug21726 },
|
||||||
|
{ "test_bug15518", test_bug15518 },
|
||||||
{ 0, 0 }
|
{ 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user