Commit 94f215cb authored by unknown's avatar unknown

Fixed bug #2248 "mysql_fetch without prior mysql_execute hangs"

Done clean-up in prep stmt API functions:
1) Removed some checks that were performed only in debug version
were making debug version more tolerable to user errors than 
production (and thus caused problems for example masking some
bugs). 
2) Also removed some other checks to make prep stmt API 
consistent with the rest of C API (this also in line with 
general politics - make checks in only those places where 
errors are very common and hard to spot).


include/mysql.h:
  Removed CHECK_EXTRA_ARGUMENTS define since it is no longer used 
  anywhere.
libmysql/libmysql.c:
  Added check that will cause mysql_fetch() to bark then it is 
  used without calling mysql_execute() before.
  Removed checks that were performed only in debug version and
  caused problems since they were making debug version more 
  tolerable to user errors than production. Also removed some
  other checks to make prep stmt API consistent in this regard 
  with the rest of C API (this also in line with general politics -
  make checks in only those places where errors are very common 
  and hard to spot).
tests/client_test.c:
  Updated tests to reflect removal of some checks in prep stmt API.
  Removed lines that caused bug #2473 to pop up, should be added 
  as separate test with the fix for this bug.
  Added test for bug#2248 "mysql_fetch without prior mysql_execute 
  hangs"
parent 63f15064
...@@ -57,9 +57,6 @@ typedef int my_socket; ...@@ -57,9 +57,6 @@ typedef int my_socket;
#include "mysql_com.h" #include "mysql_com.h"
#include "mysql_version.h" #include "mysql_version.h"
#include "typelib.h" #include "typelib.h"
#ifndef DBUG_OFF
#define CHECK_EXTRA_ARGUMENTS
#endif
#include "my_list.h" /* for LISTs used in 'MYSQL' and 'MYSQL_STMT' */ #include "my_list.h" /* for LISTs used in 'MYSQL' and 'MYSQL_STMT' */
......
...@@ -1653,14 +1653,6 @@ mysql_prepare(MYSQL *mysql, const char *query, ulong length) ...@@ -1653,14 +1653,6 @@ mysql_prepare(MYSQL *mysql, const char *query, ulong length)
DBUG_ENTER("mysql_prepare"); DBUG_ENTER("mysql_prepare");
DBUG_ASSERT(mysql != 0); DBUG_ASSERT(mysql != 0);
#ifdef CHECK_EXTRA_ARGUMENTS
if (!query)
{
set_mysql_error(mysql, CR_NULL_POINTER, unknown_sqlstate);
DBUG_RETURN(0);
}
#endif
if (!(stmt= (MYSQL_STMT *) my_malloc(sizeof(MYSQL_STMT), if (!(stmt= (MYSQL_STMT *) my_malloc(sizeof(MYSQL_STMT),
MYF(MY_WME | MY_ZEROFILL))) || MYF(MY_WME | MY_ZEROFILL))) ||
!(stmt->query= my_strdup_with_length((byte *) query, length, MYF(0)))) !(stmt->query= my_strdup_with_length((byte *) query, length, MYF(0))))
...@@ -2086,19 +2078,6 @@ int STDCALL mysql_execute(MYSQL_STMT *stmt) ...@@ -2086,19 +2078,6 @@ int STDCALL mysql_execute(MYSQL_STMT *stmt)
{ {
DBUG_ENTER("mysql_execute"); DBUG_ENTER("mysql_execute");
if (stmt->state == MY_ST_UNKNOWN)
{
set_stmt_error(stmt, CR_NO_PREPARE_STMT, unknown_sqlstate);
DBUG_RETURN(1);
}
#ifdef CHECK_EXTRA_ARGUMENTS
if (stmt->param_count && !stmt->param_buffers)
{
/* Parameters exists, but no bound buffers */
set_stmt_error(stmt, CR_NOT_ALL_PARAMS_BOUND, unknown_sqlstate);
DBUG_RETURN(1);
}
#endif
if ((*stmt->mysql->methods->stmt_execute)(stmt)) if ((*stmt->mysql->methods->stmt_execute)(stmt))
DBUG_RETURN(1); DBUG_RETURN(1);
...@@ -2144,19 +2123,6 @@ my_bool STDCALL mysql_bind_param(MYSQL_STMT *stmt, MYSQL_BIND * bind) ...@@ -2144,19 +2123,6 @@ my_bool STDCALL mysql_bind_param(MYSQL_STMT *stmt, MYSQL_BIND * bind)
MYSQL_BIND *param, *end; MYSQL_BIND *param, *end;
DBUG_ENTER("mysql_bind_param"); DBUG_ENTER("mysql_bind_param");
#ifdef CHECK_EXTRA_ARGUMENTS
if (stmt->state == MY_ST_UNKNOWN)
{
set_stmt_error(stmt, CR_NO_PREPARE_STMT, unknown_sqlstate);
DBUG_RETURN(1);
}
if (!stmt->param_count)
{
set_stmt_error(stmt, CR_NO_PARAMETERS_EXISTS, unknown_sqlstate);
DBUG_RETURN(1);
}
#endif
/* Allocated on prepare */ /* Allocated on prepare */
memcpy((char*) stmt->params, (char*) bind, memcpy((char*) stmt->params, (char*) bind,
sizeof(MYSQL_BIND) * stmt->param_count); sizeof(MYSQL_BIND) * stmt->param_count);
...@@ -2279,11 +2245,6 @@ mysql_send_long_data(MYSQL_STMT *stmt, uint param_number, ...@@ -2279,11 +2245,6 @@ mysql_send_long_data(MYSQL_STMT *stmt, uint param_number,
DBUG_PRINT("enter",("param no : %d, data : %lx, length : %ld", DBUG_PRINT("enter",("param no : %d, data : %lx, length : %ld",
param_number, data, length)); param_number, data, length));
if (param_number >= stmt->param_count)
{
set_stmt_error(stmt, CR_INVALID_PARAMETER_NO, unknown_sqlstate);
DBUG_RETURN(1);
}
param= stmt->params+param_number; param= stmt->params+param_number;
if (param->buffer_type < MYSQL_TYPE_TINY_BLOB || if (param->buffer_type < MYSQL_TYPE_TINY_BLOB ||
param->buffer_type > MYSQL_TYPE_STRING) param->buffer_type > MYSQL_TYPE_STRING)
...@@ -2853,18 +2814,6 @@ my_bool STDCALL mysql_bind_result(MYSQL_STMT *stmt, MYSQL_BIND *bind) ...@@ -2853,18 +2814,6 @@ my_bool STDCALL mysql_bind_result(MYSQL_STMT *stmt, MYSQL_BIND *bind)
DBUG_ENTER("mysql_bind_result"); DBUG_ENTER("mysql_bind_result");
DBUG_ASSERT(stmt != 0); DBUG_ASSERT(stmt != 0);
#ifdef CHECK_EXTRA_ARGUMENTS
if (stmt->state == MY_ST_UNKNOWN)
{
set_stmt_error(stmt, CR_NO_PREPARE_STMT, unknown_sqlstate);
DBUG_RETURN(1);
}
if (!bind)
{
set_stmt_error(stmt, CR_NULL_POINTER, unknown_sqlstate);
DBUG_RETURN(1);
}
#endif
if (!(bind_count= stmt->field_count) && if (!(bind_count= stmt->field_count) &&
!(bind_count= alloc_stmt_fields(stmt))) !(bind_count= alloc_stmt_fields(stmt)))
DBUG_RETURN(0); DBUG_RETURN(0);
...@@ -3035,6 +2984,15 @@ int STDCALL mysql_fetch(MYSQL_STMT *stmt) ...@@ -3035,6 +2984,15 @@ int STDCALL mysql_fetch(MYSQL_STMT *stmt)
} }
else /* un-buffered */ else /* un-buffered */
{ {
if (mysql->status != MYSQL_STATUS_GET_RESULT)
{
if (!stmt->field_count)
goto no_data;
set_stmt_error(stmt, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
DBUG_RETURN(1);
}
if((*mysql->methods->unbuffered_fetch)(mysql, ( char **)&row)) if((*mysql->methods->unbuffered_fetch)(mysql, ( char **)&row))
{ {
set_stmt_errmsg(stmt, mysql->net.last_error, mysql->net.last_errno, set_stmt_errmsg(stmt, mysql->net.last_error, mysql->net.last_errno,
...@@ -3065,7 +3023,7 @@ no_data: ...@@ -3065,7 +3023,7 @@ no_data:
mysql_fetch_column() mysql_fetch_column()
stmt Prepared statement handler stmt Prepared statement handler
bind Where data should be placed. Should be filled in as bind Where data should be placed. Should be filled in as
when calling mysql_bind_param() when calling mysql_bind_result()
column Column to fetch (first column is 0) column Column to fetch (first column is 0)
ulong offset Offset in result data (to fetch blob in pieces) ulong offset Offset in result data (to fetch blob in pieces)
This is normally 0 This is normally 0
...@@ -3083,14 +3041,6 @@ int STDCALL mysql_fetch_column(MYSQL_STMT *stmt, MYSQL_BIND *bind, ...@@ -3083,14 +3041,6 @@ int STDCALL mysql_fetch_column(MYSQL_STMT *stmt, MYSQL_BIND *bind,
if (!stmt->current_row) if (!stmt->current_row)
goto no_data; goto no_data;
#ifdef CHECK_EXTRA_ARGUMENTS
if (column >= stmt->field_count)
{
set_stmt_errmsg(stmt, "Invalid column descriptor",1, unknown_sqlstate);
DBUG_RETURN(1);
}
#endif
if (param->null_field) if (param->null_field)
{ {
if (bind->is_null) if (bind->is_null)
......
...@@ -953,8 +953,6 @@ static void test_prepare_simple() ...@@ -953,8 +953,6 @@ static void test_prepare_simple()
verify_param_count(stmt,1); verify_param_count(stmt,1);
rc = mysql_execute(stmt);
mystmt_r(stmt, rc);
mysql_stmt_close(stmt); mysql_stmt_close(stmt);
/* select */ /* select */
...@@ -5589,27 +5587,24 @@ static void test_pure_coverage() ...@@ -5589,27 +5587,24 @@ static void test_pure_coverage()
stmt = mysql_prepare(mysql,"insert into test_pure(c67788) values(10)",100); stmt = mysql_prepare(mysql,"insert into test_pure(c67788) values(10)",100);
mystmt_init_r(stmt); mystmt_init_r(stmt);
#ifndef DBUG_OFF /* Query without params and result should allow to bind 0 arrays */
stmt = mysql_prepare(mysql,(const char *)0,0);
mystmt_init_r(stmt);
stmt = mysql_prepare(mysql,"insert into test_pure(c2) values(10)",100); stmt = mysql_prepare(mysql,"insert into test_pure(c2) values(10)",100);
mystmt_init(stmt); mystmt_init(stmt);
rc = mysql_bind_param(stmt, bind); rc = mysql_bind_param(stmt, (MYSQL_BIND*)0);
mystmt_r(stmt, rc); mystmt(stmt, rc);
rc = mysql_execute(stmt);
mystmt(stmt, rc);
rc = mysql_bind_result(stmt, (MYSQL_BIND*)0);
mystmt(stmt, rc);
mysql_stmt_close(stmt); mysql_stmt_close(stmt);
#endif
stmt = mysql_prepare(mysql,"insert into test_pure(c2) values(?)",100); stmt = mysql_prepare(mysql,"insert into test_pure(c2) values(?)",100);
mystmt_init(stmt); mystmt_init(stmt);
#ifndef DBUG_OFF
rc = mysql_execute(stmt);
mystmt_r(stmt, rc);/* No parameters supplied */
#endif
bind[0].length= &length; bind[0].length= &length;
bind[0].is_null= 0; bind[0].is_null= 0;
bind[0].buffer_length= 0; bind[0].buffer_length= 0;
...@@ -5622,9 +5617,6 @@ static void test_pure_coverage() ...@@ -5622,9 +5617,6 @@ static void test_pure_coverage()
rc = mysql_bind_param(stmt, bind); rc = mysql_bind_param(stmt, bind);
mystmt(stmt, rc); mystmt(stmt, rc);
rc = mysql_send_long_data(stmt, 20, (char *)"venu", 4);
mystmt_r(stmt, rc); /* wrong param number */
rc = mysql_stmt_store_result(stmt); rc = mysql_stmt_store_result(stmt);
mystmt(stmt, rc); mystmt(stmt, rc);
...@@ -5636,14 +5628,9 @@ static void test_pure_coverage() ...@@ -5636,14 +5628,9 @@ static void test_pure_coverage()
rc = mysql_execute(stmt); rc = mysql_execute(stmt);
mystmt(stmt, rc); mystmt(stmt, rc);
#ifndef DBUG_OFF
rc = mysql_bind_result(stmt, (MYSQL_BIND *)0);
mystmt_r(stmt, rc);
bind[0].buffer_type= MYSQL_TYPE_GEOMETRY; bind[0].buffer_type= MYSQL_TYPE_GEOMETRY;
rc = mysql_bind_result(stmt, bind); rc = mysql_bind_result(stmt, bind);
mystmt_r(stmt, rc); /* unsupported buffer type */ mystmt_r(stmt, rc); /* unsupported buffer type */
#endif
rc = mysql_stmt_store_result(stmt); rc = mysql_stmt_store_result(stmt);
mystmt(stmt, rc); mystmt(stmt, rc);
...@@ -7291,9 +7278,6 @@ static void test_fetch_offset() ...@@ -7291,9 +7278,6 @@ static void test_fetch_offset()
rc = mysql_fetch(stmt); rc = mysql_fetch(stmt);
mystmt(stmt,rc); mystmt(stmt,rc);
rc = mysql_fetch_column(stmt,bind,4,0);
mystmt_r(stmt,rc);
data[0]= '\0'; data[0]= '\0';
rc = mysql_fetch_column(stmt,bind,0,0); rc = mysql_fetch_column(stmt,bind,0,0);
mystmt(stmt,rc); mystmt(stmt,rc);
...@@ -7411,9 +7395,6 @@ static void test_fetch_column() ...@@ -7411,9 +7395,6 @@ static void test_fetch_column()
fprintf(stdout, "\n col 0: %d(%ld)", c1, l1); fprintf(stdout, "\n col 0: %d(%ld)", c1, l1);
assert(c1 == 1 && l1 == 4); assert(c1 == 1 && l1 == 4);
rc = mysql_fetch_column(stmt,bind,10,0);
mystmt_r(stmt,rc);
rc = mysql_fetch(stmt); rc = mysql_fetch(stmt);
mystmt(stmt,rc); mystmt(stmt,rc);
...@@ -8096,6 +8077,64 @@ static void test_bug1946() ...@@ -8096,6 +8077,64 @@ static void test_bug1946()
} }
/*
Test for bug#2248 "mysql_fetch without prior mysql_execute hangs"
*/
static void test_bug2248()
{
MYSQL_STMT *stmt;
int rc;
const char *query1= "SELECT DATABASE()";
const char *query2= "INSERT INTO test_bug2248 VALUES (10)";
myheader("test_bug2248");
rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_bug2248");
myquery(rc);
rc= mysql_query(mysql, "CREATE TABLE test_bug2248 (id int)");
myquery(rc);
stmt= mysql_prepare(mysql, query1, strlen(query1));
mystmt_init(stmt);
/* This should not hang */
rc= mysql_fetch(stmt);
mystmt_r(stmt,rc);
/* And this too */
rc= mysql_stmt_store_result(stmt);
mystmt_r(stmt,rc);
mysql_stmt_close(stmt);
stmt= mysql_prepare(mysql, query2, strlen(query2));
mystmt_init(stmt);
rc= mysql_execute(stmt);
mystmt(stmt,rc);
/* This too should not hang but should return proper error */
rc= mysql_fetch(stmt);
assert(rc==MYSQL_NO_DATA);
/* This too should not hang but should not bark */
rc= mysql_stmt_store_result(stmt);
mystmt(stmt,rc);
/* This should return proper error */
rc= mysql_fetch(stmt);
mystmt_r(stmt,rc);
assert(rc==MYSQL_NO_DATA);
mysql_stmt_close(stmt);
rc= mysql_query(mysql,"DROP TABLE test_bug2248");
myquery(rc);
}
/* /*
Read and parse arguments and MySQL options from my.cnf Read and parse arguments and MySQL options from my.cnf
*/ */
...@@ -8340,6 +8379,7 @@ int main(int argc, char **argv) ...@@ -8340,6 +8379,7 @@ int main(int argc, char **argv)
test_bug1644(); /* BUG#1644 */ test_bug1644(); /* BUG#1644 */
test_bug1946(); /* test that placeholders are allowed only in test_bug1946(); /* test that placeholders are allowed only in
prepared queries */ prepared queries */
test_bug2248(); /* BUG#2248 */
end_time= time((time_t *)0); end_time= time((time_t *)0);
total_time+= difftime(end_time, start_time); total_time+= difftime(end_time, start_time);
......
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