| Bug #24645 | Error with mysql_stmt_bind_param | ||
|---|---|---|---|
| Submitted: | 28 Nov 2006 5:42 | Modified: | 20 Mar 2007 15:45 |
| Reporter: | Mike Rollins | Email Updates: | |
| Status: | No Feedback | Impact on me: | |
| Category: | MySQL Server | Severity: | S2 (Serious) |
| Version: | 4.1.21, 4.1.22 | OS: | Linux (linux) |
| Assigned to: | CPU Architecture: | Any | |
[28 Nov 2006 5:46]
Mike Rollins
Create Tables
Attachment: create_tables.bash (application/octet-stream, text), 674 bytes.
[28 Nov 2006 5:46]
Mike Rollins
Makefile
Attachment: Makefile (application/octet-stream, text), 410 bytes.
[28 Nov 2006 5:47]
Mike Rollins
Example C program
Attachment: sqltest.c (application/octet-stream, text), 4.26 KiB.
[28 Nov 2006 8:13]
Valeriy Kravchuk
Thank you for a problem report. Please, send the exact configure command line you had used.
[29 Nov 2006 0:04]
Mike Rollins
The configure command is as follows: ./configure --prefix=/usr/local/mysql --with-mysqld-user=mysql I will attach a copy of the config.log file.
[29 Nov 2006 0:07]
Mike Rollins
config.log file
Attachment: config.log.gz (application/x-gzip, text), 31.44 KiB.
[3 Dec 2006 9:27]
Valeriy Kravchuk
Please, try to repeat with a newer version, 4.1.22, and inform about the results.
[3 Dec 2006 13:15]
Mike Rollins
I reproduced the problem with 4.1.22
[3 Dec 2006 22:15]
Mike Rollins
This is interesting. If I add the --with-debug to my configure command, the resulting binary will work correctly. I was going to see what I could learn from the trace output and realized my test program worked. I then configured/compiled/installed without the debug option and the problem came back.
[4 Dec 2006 20:26]
Sveta Smirnova
Thank you for the report. I can not repeat it using binaries compiled with --debug option and without it.
[5 Dec 2006 2:39]
Mike Rollins
I did some digging in the code and have found the following:
I added a print statement to the set_param_int32 function in the file sql/sql_prepare.cc.
static void set_param_int32(Item_param *param, uchar **pos, ulong len)
{
int32 value;
uchar *mike = *pos;
for (ulong i=0; i<len; i++)
fprintf(stderr,"MIKE set_param_int32 pos[%d]: %x\n",i,*(mike+i));
When running the program I see the following:
MIKE set_param_int32 pos[0]: 0
MIKE set_param_int32 pos[1]: 1
MIKE set_param_int32 pos[2]: 3
MIKE set_param_int32 pos[3]: 0
MIKE set_param_int32 pos[4]: 1
MIKE set_param_int32 pos[5]: 0
MIKE set_param_int32 pos[6]: 0
MIKE set_param_int32 pos[7]: 0
When 0130 is cast to a long, the value becomes 196864. This is what I see in the query log. The next four bytes 1000 is the value of my parameter.
It appears that this function should be called without the first four bytes, just the last four bytes of this packet.
[6 Dec 2006 10:21]
Sveta Smirnova
Please indicate accurate platform you use
[6 Dec 2006 11:31]
Mike Rollins
cat /proc/version Linux version 2.6.18 (rollins@bobby.goodhotdogs.com) (gcc version 4.1.0 20060304 (Red Hat 4.1.0-3)) #1 SMP Wed Nov 15 20:16:34 EST 2006 [rollins@bobby bug]$ uname -s Linux [rollins@bobby bug]$ uname -r 2.6.18 [rollins@bobby bug]$ uname -v #1 SMP Wed Nov 15 20:16:34 EST 2006 [rollins@bobby bug]$ uname -m i686 [rollins@bobby bug]$ uname -p i686 [rollins@bobby bug]$ uname -i i386 [rollins@bobby bug]$ uname -o GNU/Linux
[7 Dec 2006 3:27]
Mike Rollins
I found something interesting. The following three steps will show what I have found:
Step 1:
Modify the file: sql/sql_prepare.cc
Find the function: insert_params_withlog
After the DBUG_ENTER statement add the following:
fprintf(stderr,"MIKE: insert_params_withlog: read_pos = %x\n",read_pos);
for (uchar* mike = read_pos; mike <=data_end; mike++)
fprintf(stderr,"MIKE: insert_params_withlog: %x\n",*mike);
The output of the test program will yield the following in the log file:
MIKE: insert_params_withlog: read_pos = 897048a
MIKE: insert_params_withlog: 0
MIKE: insert_params_withlog: 1
MIKE: insert_params_withlog: 3
MIKE: insert_params_withlog: 0
MIKE: insert_params_withlog: 1
MIKE: insert_params_withlog: 0
MIKE: insert_params_withlog: 0
MIKE: insert_params_withlog: 0
MIKE: insert_params_withlog: 0
Step 2:
Find the function: setup_conversion_functions
The end of the function is as follows:
}
}
*data= read_pos;
DBUG_RETURN(0);
}
Add a print statement
}
fprintf(stderr,"MIKE: E: setup_conversion_functions %x\n",read_pos);
}
*data= read_pos;
DBUG_RETURN(0);
}
The output is now as follows:
MIKE: E: setup_conversion_functions 897048e
MIKE: insert_params_withlog: read_pos = 897048a
MIKE: insert_params_withlog: 0
MIKE: insert_params_withlog: 1
MIKE: insert_params_withlog: 3
MIKE: insert_params_withlog: 0
MIKE: insert_params_withlog: 1
MIKE: insert_params_withlog: 0
MIKE: insert_params_withlog: 0
MIKE: insert_params_withlog: 0
MIKE: insert_params_withlog: 0
For some reason, the "*data= read_pos" line does not seem to be
updating the *data variable.
Step 3:
The last step is "magical". In this step, add one more print statement
to the end of the setup_conversion_functions function.
}
fprintf(stderr,"MIKE: E: setup_conversion_functions %x\n",read_pos);
}
fprintf(stderr,"MIKE\n");
*data= read_pos;
DBUG_RETURN(0);
}
The output is now:
MIKE: E: setup_conversion_functions 897048e
MIKE
MIKE: insert_params_withlog: read_pos = 897048e
MIKE: insert_params_withlog: 1
MIKE: insert_params_withlog: 0
MIKE: insert_params_withlog: 0
MIKE: insert_params_withlog: 0
MIKE: insert_params_withlog: 0
Conclusion:
Somehow, adding a print statement before the "*data= read_pos;" statement
will allow the *data value to be updated successfully. I don't understand
this.
[8 Dec 2006 2:18]
Mike Rollins
In the file "sql/sql_prepare.cc", I found that the problem goes away if I remove the static from the function setup_conversion_functions.
Change
static bool setup_conversion_functions(Prepared_statement *stmt,
uchar **data, uchar *data_end)
to
bool setup_conversion_functions(Prepared_statement *stmt,
uchar **data, uchar *data_end)
[30 Dec 2006 9:40]
Valeriy Kravchuk
Please, send the results of gcc --version If it is the same gcc version 4.1.0 as mentioned in uname results, it can be gcc bug (or bug/problem in MySQL that gcc 4.x.y can pinpoint).
[30 Dec 2006 12:38]
Mike Rollins
My current version of gcc:
[rollins@bobby bug]$ gcc --version
gcc (GCC) 4.1.0 20060304 (Red Hat 4.1.0-3)
WITH STATIC:
I did the test with the "static bool"
vi sql/sql_prepare.cc
static bool setup_conversion_functions(Prepared_statement *stmt,
uchar **data, uchar *data_end)
The log file shows
2 Execute [1] select PK, VALUE from TEST where PK = 196864
WITHOUT STATIC:
I did the test without the "static bool"
vi sql/sql_prepare.cc
bool setup_conversion_functions(Prepared_statement *stmt,
uchar **data, uchar *data_end)
The log file shows
2 Execute [1] select PK, VALUE from TEST where PK = 1
I updated GCC
yum update gcc
Dependencies Resolved
=============================================================================
Package Arch Version Repository Size
=============================================================================
Updating:
gcc i386 4.1.1-1.fc5 updates 4.6 M
Updating for dependencies:
cpp i386 4.1.1-1.fc5 updates 2.6 M
gcc-c++ i386 4.1.1-1.fc5 updates 3.3 M
gcc-gfortran i386 4.1.1-1.fc5 updates 2.8 M
gcc-java i386 4.1.1-1.fc5 updates 2.8 M
libgcc i386 4.1.1-1.fc5 updates 61 k
libgcj i386 4.1.1-1.fc5 updates 12 M
libgcj-devel i386 4.1.1-1.fc5 updates 1.3 M
libgcj-src i386 4.1.1-1.fc5 updates 8.3 M
libgfortran i386 4.1.1-1.fc5 updates 194 k
libgomp i386 4.1.1-1.fc5 updates 48 k
libstdc++ i386 4.1.1-1.fc5 updates 324 k
libstdc++-devel i386 4.1.1-1.fc5 updates 9.5 M
libtool i386 1.5.22-2.3 updates 678 k
Now, my current version of GCC is
gcc (GCC) 4.1.1 20060525 (Red Hat 4.1.1-1)
I recompiled mysql-4.1.22
make clean
make && make install
WITH STATIC:
I did the test with the "static bool"
vi sql/sql_prepare.cc
static bool setup_conversion_functions(Prepared_statement *stmt,
uchar **data, uchar *data_end)
The log file shows
2 Execute [1] select PK, VALUE from TEST where PK = 196864
WITHOUT STATIC:
I did the test without the "static bool"
vi sql/sql_prepare.cc
bool setup_conversion_functions(Prepared_statement *stmt,
uchar **data, uchar *data_end)
The log file shows
2 Execute [1] select PK, VALUE from TEST where PK = 1
I even rebooted and performed a clean install of 4.1.22 and had the same results.
[20 Feb 2007 15:45]
Valeriy Kravchuk
Please, try to compile with a newer version of gcc, 4.1.1 (or 4.1.2). In case of the same problem, please, send all CFLAGS/CXXFLAGS used. I still think it was a compiler bug.
[21 Mar 2007 0:00]
Bugs System
No feedback was provided for this bug for over a month, so it is being suspended automatically. If you are able to provide the information that was originally requested, please do so and change the status of the bug back to "Open".

Description: Attempts to bind values (integer values) to a prepared statment is not successfull with the compiled version of mysql. However, the same C program works correctly if I use the pre-compiled verion of mysql. Compiled Version: mysql: 4.1.21 gcc: 4.1.0 glibc: 2.4-4 Linux: 2.6.18 CFLAGS = -I/usr/local/mysql/include/mysql CLIBS = -L/usr/local/mysql/lib/mysql -lmysqlclient -lz -lcrypt -lnsl -lm If I use the binary version of mysql with the static 2.2 glibc the same C program works correctly: Linux (x86, glibc-2.2, "standard" is static, gcc) mysql-standard-4.1.21-pc-linux-gnu-i686.tar.gz CFLAGS = -I/usr/local/mysql/include -mcpu=pentiumpro CLIBS = -L/usr/local/lib -L/usr/local/mysql/lib -lmysqlclient -lz \ -lcrypt -lnsl -lm -lc -lnss_files -lnss_dns -lresolv -lc \ -lnss_files -lnss_dns -lresolv How to repeat: #!/bin/bash MYSQLADMIN=/usr/local/mysql/bin/mysqladmin MYSQL=/usr/local/mysql/bin/mysql ${MYSQLADMIN} -u root drop testdb --password=XXXX -f ${MYSQLADMIN} -u root create testdb --password=XXXX ${MYSQL} -u root testdb --password=XXXX <<EOF GRANT ALL PRIVILEGES ON testdb.* TO 'testuser'@'localhost' IDENTIFIED BY 'testpassword'; quit EOF ${MYSQL} -u testuser testdb --password=testpassword <<EOF create table TEST ( PK int, VALUE int ) ENGINE=MyISAM; insert into TEST (PK,VALUE) values (1,10); insert into TEST (PK,VALUE) values (2,20); insert into TEST (PK,VALUE) values (3,30); EOF echo ${MYSQL} -u testuser testdb --password=testpassword +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ #include <mysql.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #define DB_DBNAME "testdb" #define DB_DBUSER "testuser" #define DB_DBPWD "testpassword" #define DB_DBHOST "localhost" #define DB_DBPORT 3306 int main() { /* this query returns all the rows successfully */ //char *query = "select PK, VALUE from TEST"; /* This query, with an input_buffer value of 1, does not return anything. */ /* The query log shows that the value of the bind variable is 196864, not the value of 1 */ /* that is in the buffer. The following shows the contents of the query log: */ /* 061127 21:47:31 28 Connect testuser@localhost on testdb */ /* 28 Prepare [1] select PK, VALUE from TEST where PK = ? */ /* 28 Execute [1] select PK, VALUE from TEST where PK = 196864 */ /* 28 Quit */ /* The query work correctly if I use the binary distribution of mysql instead of the */ /* version that I compiled myself: */ /* 061127 23:31:36 12 Connect testuser@localhost on testdb */ /* 12 Prepare [1] select PK, VALUE from TEST where PK = ? */ /* 12 Execute [1] select PK, VALUE from TEST where PK = 1 */ /* 12 Quit */ char *query = "select PK, VALUE from TEST where PK = ?"; MYSQL *mysql; MYSQL_STMT *stmt; MYSQL_BIND params[1]; int input_buffer; /* Setup prepared statement parameters */ memset(params, 0, sizeof(params)); params[0].buffer_type = MYSQL_TYPE_LONG; params[0].buffer = (int*) &input_buffer; input_buffer = 1; /*******************/ /* Result set data */ /*******************/ MYSQL_BIND col[2]; /* Result Set Buffers */ my_bool is_null[2]; unsigned long length[2]; int pk_buffer; int value_buffer; /* initialize mysql */ mysql = mysql_init((void *)NULL); if (!mysql) { printf("mysql_init(): %s\n", mysql_error(mysql)); return 1; } /* connect to the database */ if (mysql_real_connect(mysql, DB_DBHOST, DB_DBUSER, DB_DBPWD, DB_DBNAME, DB_DBPORT, NULL, 0) == NULL) { printf("mysql_real_connect(): %s\n", mysql_error(mysql)); return 1; } /* Create a prepared statement */ stmt = mysql_stmt_init(mysql); if (!stmt) { printf("mysql_stmt_init(): %s\n", mysql_error(mysql)); return 1; } /* Attach the query */ if (mysql_stmt_prepare(stmt, query, strlen(query))) { printf("mysql_stmt_prepare(): %s\n", mysql_error(mysql)); return 1; } /* Bind the input buffers */ if (mysql_stmt_bind_param(stmt, params)) { fprintf(stderr, " mysql_stmt_bind_param() failed\n"); fprintf(stderr, " %s\n", mysql_stmt_error(stmt)); return 1; } /* Execute the query */ if (mysql_stmt_execute(stmt)) { printf(" mysql_stmt_execute(), 1 failed\n"); printf(" %s\n", mysql_stmt_error(stmt)); return 1; } /* Setup the result buffers */ /* INTEGER COLUMN */ col[0].buffer_type= MYSQL_TYPE_LONG; col[0].buffer= (char *)&pk_buffer; col[0].is_null= &is_null[0]; col[0].length= &length[0]; /* INTEGER COLUMN */ col[1].buffer_type= MYSQL_TYPE_LONG; col[1].buffer= (char *)&value_buffer; col[1].is_null= &is_null[1]; col[1].length= &length[1]; /* Bind the result buffers */ if (mysql_stmt_bind_result(stmt, col)) { printf(" mysql_stmt_bind_result(), 1 failed\n"); printf(" %s\n", mysql_stmt_error(stmt)); return ; } /* fetch the results */ while (!mysql_stmt_fetch(stmt)) { printf("PK: %d, Value: %d\n",pk_buffer,value_buffer); } if (mysql_stmt_close(stmt)) { fprintf(stderr, " failed while closing the statement\n"); fprintf(stderr, " %s\n", mysql_stmt_error(stmt)); exit(0); } mysql_close(mysql); return 0; }