Description:
My Environment:
* MyODBC Version: 5.2.6
* Using visual studio 2008 and cpp project.
Requiremets:
* Mysql store procedure has more than one input parameter and more than one output parameter.
* Output parameter must be precedence than Input parameter
(ex first parameter is output parameter, and second parameter is input parameter.)
Where:
in driver/my_prepared_stmt.c file ssps_get_out_params function
<pre>
if (values != NULL && got_out_parameters(stmt))
{
for (i= 0; i < myodbc_min(stmt->ipd->count, stmt->apd->count); ++i)
{
/* Making bit field look "normally" */
HERE>> if (stmt->result_bind[counter].buffer_type == MYSQL_TYPE_BIT)
{
</pre>
Description:
The for loop iterate all input or output parameters. But stmt->result_bind variable is only valid for output parameter. So when iterate input parameter, stmt->result_bind[counter] is not valid memory address.
How to repeat:
We need simple store procedure which has output parameter and input parameter. For example.
<pre>
DELIMITER $$
CREATE DEFINER=`root`@`localhost` PROCEDURE `TEST`(
out dummy int,
in dumm int
)
BEGIN
begin
set dumm = 3;
end;
END
</pre>
And call the procedure with odbc driver. It always access bad memory. Check it with debugger.
Suggested fix:
Make result_bind[counter] access code executed only when output parameter. So move that code to below if block which is only called when output or input_output parameter.
*** mysql-connector-odbc-5.2.6-src/driver/my_prepared_stmt.c Thu Sep 26 01:59:00 2013
--- mysql-connector-odbc-5.2.6-src-patched/driver/my_prepared_stmt.c Thu Oct 17 10:12:55 2013
***************
*** 127,149 ****
{
for (i= 0; i < myodbc_min(stmt->ipd->count, stmt->apd->count); ++i)
{
- /* Making bit field look "normally" */
- if (stmt->result_bind[counter].buffer_type == MYSQL_TYPE_BIT)
- {
- MYSQL_FIELD *field= mysql_fetch_field_direct(stmt->result, counter);
- unsigned long long numeric;
-
- assert(field->type == MYSQL_TYPE_BIT);
- /* terminating with NULL */
- values[counter][*stmt->result_bind[counter].length]= '\0';
- numeric= strtoull(values[counter], NULL, 10);
-
- *stmt->result_bind[counter].length= (field->length+7)/8;
- numeric2binary(values[counter], numeric,
- *stmt->result_bind[counter].length);
-
- }
-
iprec= desc_get_rec(stmt->ipd, i, FALSE);
aprec= desc_get_rec(stmt->apd, i, FALSE);
assert(iprec && aprec);
--- 127,132 ----
***************
*** 151,156 ****
--- 134,156 ----
if ((iprec->parameter_type == SQL_PARAM_INPUT_OUTPUT
|| iprec->parameter_type == SQL_PARAM_OUTPUT))
{
+ /* Making bit field look "normally" */
+ if (stmt->result_bind[counter].buffer_type == MYSQL_TYPE_BIT)
+ {
+ MYSQL_FIELD *field= mysql_fetch_field_direct(stmt->result, counter);
+ unsigned long long numeric;
+
+ assert(field->type == MYSQL_TYPE_BIT);
+ /* terminating with NULL */
+ values[counter][*stmt->result_bind[counter].length]= '\0';
+ numeric= strtoull(values[counter], NULL, 10);
+
+ *stmt->result_bind[counter].length= (field->length+7)/8;
+ numeric2binary(values[counter], numeric,
+ *stmt->result_bind[counter].length);
+
+ }
+
if (aprec->data_ptr)
{
unsigned long length= *stmt->result_bind[counter].length;