Description:
We found a bug with MySQL Connector ODBC 5.2.5 when we compile and run on IBM PowerLinux with RHEL 6.
A segfault would occur during statement execute whenever we were using parameter markers.
Looked through the code and found the bug. Correcting the bug and rebuilding seems to have fixed our problem. See "Suggested fix" section.
I believe we get away with this on x86 architectures due to x86 being little endian.
How to repeat:
Any simple program using parameter markers on IBM PowerLinux. Here is an example I used to recreate:
// CREATE TABLE T1 (F1 INTEGER)
#include <iostream>
#include <sql.h>
#include <sqlext.h>
using namespace std;
int main() {
SQLHENV henv;
SQLHDBC hdbc;
SQLHSTMT hstmt;
if (SQL_SUCCESS != SQLAllocHandle(SQL_HANDLE_ENV,
SQL_NULL_HANDLE,
&henv)) {
cout << "SQLAllocHandle error" << endl;
return -1;
}
if (SQL_SUCCESS != SQLSetEnvAttr(henv,
SQL_ATTR_ODBC_VERSION,
(void*)SQL_OV_ODBC3,
0)) {
cout << "SQLSetEnvAttr error" << endl;
return -1;
}
if (SQL_SUCCESS != SQLAllocHandle(SQL_HANDLE_DBC,
henv,
&hdbc)) {
cout << "SQLAllocHandle error(2)" << endl;
return -1;
}
if (SQL_SUCCESS != SQLConnect(hdbc,
(SQLCHAR*) "mysqltest",
SQL_NTS,
(SQLCHAR*) "USER",
SQL_NTS,
(SQLCHAR*) "PASSWORD",
SQL_NTS)) {
cout << "SQLConnect error" << endl;
return -1;
}
if (SQL_SUCCESS != SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt)) {
cout << "SQLAllocHandle error(3)" << endl;
return -1;
}
if (SQL_SUCCESS != SQLPrepare(hstmt,
(SQLCHAR*) "insert into T1 values (?)",
SQL_NTS)) {
cout << "SQLPrepare error" << endl;
return -1;
}
SQLLEN ind = 0;
SQLINTEGER value = 5;
if (SQL_SUCCESS != SQLBindParameter(hstmt,
1,
SQL_PARAM_INPUT,
SQL_C_LONG,
SQL_INTEGER,
0,
0,
&value,
0,
&ind)) {
cout << "SQLBindParameter error" << endl;
return -1;
}
if (SQL_SUCCESS != SQLExecute(hstmt)) {
cout << "SQLExecute error" << endl;
return -1;
}
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
SQLDisconnect(hdbc);
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
SQLFreeHandle(SQL_HANDLE_ENV, henv);
return 0;
}
Suggested fix:
Bug is in file mysql-connector-odbc-5.2.5-src/driver/execute.c.
Function insert_param() has this variable:
long length;
insert_param() also calls convert_c_type2str() as follows:
switch(convert_c_type2str(stmt, aprec->concise_type, iprec,
&data, &length, buff, sizeof(buff)))
The signature for convert_c_type2str is as follows:
static
SQLRETURN convert_c_type2str(STMT *stmt, SQLSMALLINT ctype, DESCREC *iprec,
char **res, int *length, char *buff, uint buff_max)
Note that legnth is a long in insert_param(), but is an int* in c_type2str.
I changed the declaration of length in convert_c_type2str to long and the problem went away in my simple testcase at least..
The code now looks like this:
SQLRETURN convert_c_type2str(STMT *stmt, SQLSMALLINT ctype, DESCREC *iprec,
char **res, long *length, char *buff, uint buff_max)