Commit e42d9085 authored by Davi Arnaut's avatar Davi Arnaut

Bug#54041: MySQL 5.0.92 fails when tests from Connector/C suite run

The problem was that a user could supply supply data in chunks
via the COM_STMT_SEND_LONG_DATA command to prepared statement
parameter other than of type TEXT or BLOB. This posed a problem
since other parameter types aren't setup to handle long data,
which would lead to a crash when attempting to use the supplied
data.

Given that long data can be supplied at any stage of a prepared
statement, coupled with the fact that the type of a parameter
marker might change between consecutive executions, the solution
is to validate at execution time each parameter marker for which
a data stream was provided. If the parameter type is not TEXT or
BLOB (that is, if the type is not able to handle a data stream),
a error is returned.

sql/sql_prepare.cc:
  Before converting the parameter data stream, check the type
  compatibility.
tests/mysql_client_test.c:
  Add test case.
parent 609e65ba
...@@ -674,6 +674,18 @@ static void setup_one_conversion_function(THD *thd, Item_param *param, ...@@ -674,6 +674,18 @@ static void setup_one_conversion_function(THD *thd, Item_param *param,
} }
#ifndef EMBEDDED_LIBRARY #ifndef EMBEDDED_LIBRARY
/**
Check whether this parameter data type is compatible with long data.
Used to detect whether a long data stream has been supplied to a
incompatible data type.
*/
inline bool is_param_long_data_type(Item_param *param)
{
return ((param->param_type >= MYSQL_TYPE_TINY_BLOB) &&
(param->param_type <= MYSQL_TYPE_STRING));
}
/* /*
Routines to assign parameters from data supplied by the client. Routines to assign parameters from data supplied by the client.
...@@ -737,6 +749,14 @@ static bool insert_params_withlog(Prepared_statement *stmt, uchar *null_array, ...@@ -737,6 +749,14 @@ static bool insert_params_withlog(Prepared_statement *stmt, uchar *null_array,
DBUG_RETURN(1); DBUG_RETURN(1);
} }
} }
/*
A long data stream was supplied for this parameter marker.
This was done after prepare, prior to providing a placeholder
type (the types are supplied at execute). Check that the
supplied type of placeholder can accept a data stream.
*/
else if (!is_param_long_data_type(param))
DBUG_RETURN(1);
res= param->query_val_str(&str); res= param->query_val_str(&str);
if (param->convert_str_value(thd)) if (param->convert_str_value(thd))
DBUG_RETURN(1); /* out of memory */ DBUG_RETURN(1); /* out of memory */
...@@ -775,6 +795,14 @@ static bool insert_params(Prepared_statement *stmt, uchar *null_array, ...@@ -775,6 +795,14 @@ static bool insert_params(Prepared_statement *stmt, uchar *null_array,
DBUG_RETURN(1); DBUG_RETURN(1);
} }
} }
/*
A long data stream was supplied for this parameter marker.
This was done after prepare, prior to providing a placeholder
type (the types are supplied at execute). Check that the
supplied type of placeholder can accept a data stream.
*/
else if (is_param_long_data_type(param))
DBUG_RETURN(1);
if (param->convert_str_value(stmt->thd)) if (param->convert_str_value(stmt->thd))
DBUG_RETURN(1); /* out of memory */ DBUG_RETURN(1); /* out of memory */
} }
......
...@@ -16757,6 +16757,63 @@ static void test_bug53907() ...@@ -16757,6 +16757,63 @@ static void test_bug53907()
} }
/**
Bug#54041: MySQL 5.0.92 fails when tests from Connector/C suite run
*/
static void test_bug54041()
{
int rc;
MYSQL_STMT *stmt;
MYSQL_BIND bind;
DBUG_ENTER("test_bug54041");
myheader("test_bug54041");
rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
myquery(rc);
rc= mysql_query(mysql, "CREATE TABLE t1 (a INT)");
myquery(rc);
stmt= mysql_simple_prepare(mysql, "INSERT INTO t1 (a) VALUES (?)");
check_stmt(stmt);
verify_param_count(stmt, 1);
memset(&bind, 0, sizeof(bind));
/* Any type that does not support long data handling. */
bind.buffer_type= MYSQL_TYPE_LONG;
rc= mysql_stmt_bind_param(stmt, &bind);
check_execute(stmt, rc);
/*
Trick the client API into sending a long data packet for
the parameter. Long data is only supported for string and
binary types.
*/
stmt->params[0].buffer_type= MYSQL_TYPE_STRING;
rc= mysql_stmt_send_long_data(stmt, 0, "data", 5);
check_execute(stmt, rc);
/* Undo API violation. */
stmt->params[0].buffer_type= MYSQL_TYPE_LONG;
rc= mysql_stmt_execute(stmt);
/* Incorrect arguments. */
check_execute_r(stmt, rc);
mysql_stmt_close(stmt);
rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
myquery(rc);
DBUG_VOID_RETURN;
}
/* /*
Read and parse arguments and MySQL options from my.cnf Read and parse arguments and MySQL options from my.cnf
*/ */
...@@ -17062,6 +17119,7 @@ static struct my_tests_st my_tests[]= { ...@@ -17062,6 +17119,7 @@ static struct my_tests_st my_tests[]= {
{ "test_bug45010", test_bug45010 }, { "test_bug45010", test_bug45010 },
{ "test_bug53371", test_bug53371 }, { "test_bug53371", test_bug53371 },
{ "test_bug53907", test_bug53907 }, { "test_bug53907", test_bug53907 },
{ "test_bug54041", test_bug54041 },
{ 0, 0 } { 0, 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