Bug #5254 | Prepared Statement C API does not work | ||
---|---|---|---|
Submitted: | 27 Aug 2004 15:13 | Modified: | 7 Sep 2004 15:48 |
Reporter: | Rick Robinson | Email Updates: | |
Status: | Not a Bug | Impact on me: | |
Category: | MySQL Server | Severity: | S2 (Serious) |
Version: | 4.1.3 beta | OS: | Solaris (Solaris 9 Sparc) |
Assigned to: | Konstantin Osipov | CPU Architecture: | Any |
[27 Aug 2004 15:13]
Rick Robinson
[30 Aug 2004 20:02]
Hartmut Holzgraefe
Verified with gcc 3.3.1 (SuSE 9.0). Happens with libmysqlclient_r while regular libmysqlclient works fine.
[30 Aug 2004 22:50]
Rick Robinson
I see that the problem was replicated - but it begs the question; is this a problem with just prepared statements and the reentrant lib or should I be concerned about using the reentrant lib with 4.1.3 for anything else? Thx, R
[7 Sep 2004 15:48]
Konstantin Osipov
Hello Rick. After fixing a few bugs in your test case, I wasn't able to repeat the bug. Both, libmysqlclient_r and libmysqlclient work fine. In contrary, if I try the original test case, it fails, no matter how it's compiled. See the modified test case below. You shouldn't have set bind[i].length to point to uninitialized lengths - on input, bind[i].length should be set only if length varies from execute to execute. If this is the case, then you can reset lengths before calling mysql_stmt_execute, without having to rebind parameters each time. #include <iostream> #include <cstdlib> #include <cstring> #include <cstdio> #include "mysql.h" using namespace std; int main(int argc, char *argv[]) { cout << "start up" << endl; MYSQL * connection; connection = mysql_init(0); // update for your own environment connection = mysql_real_connect(connection, 0, "root", "", "test", 0, "/opt/local/var/mysql/mysql.sock", 0); if (0 == connection) { cerr << "connect failed:" << mysql_error(connection) << endl; return -1; } static const char * sql_statement = "select property_value from cfg_2 " "where config_key=? and section_key=? and property_key=?"; MYSQL_STMT * stmt_handle = mysql_stmt_init(connection); if (0 == stmt_handle) { cerr << "stmt init failed:" << mysql_error(connection) << endl; return -1; } int mysql_return_code = mysql_stmt_prepare(stmt_handle, sql_statement, strlen(sql_statement) ); if (0 != mysql_return_code) { cerr << "stmt prepare failed:" << mysql_stmt_error(stmt_handle) << endl; mysql_stmt_close(stmt_handle); return -1; } MYSQL_BIND bind_var[3]; unsigned long var_length[3]; my_bool not_null = 0; char config_key[31] = {'\0'}; char section_key[31] = {'\0'}; char property_key[256] = {'\0'}; bzero(bind_var, sizeof(bind_var)); bind_var[0].buffer_type = MYSQL_TYPE_VAR_STRING; bind_var[0].buffer = (char *)config_key; bind_var[0].buffer_length = sizeof(config_key); bind_var[0].is_null = ¬_null; bind_var[1].buffer_type = MYSQL_TYPE_VAR_STRING; bind_var[1].buffer = (char *)section_key; bind_var[1].buffer_length = sizeof(section_key); bind_var[1].is_null = ¬_null; bind_var[2].buffer_type = MYSQL_TYPE_VAR_STRING; bind_var[2].buffer = (char *)property_key; bind_var[2].buffer_length = sizeof(property_key); bind_var[2].is_null = ¬_null; strncpy(config_key, "svp001", sizeof(section_key)-1); strncpy(section_key, "stats", sizeof(section_key)-1); strncpy(property_key, "number.of.threads", sizeof(property_key)-1); mysql_return_code = mysql_stmt_bind_param(stmt_handle, bind_var); if (0 != mysql_return_code) { cerr << "stmt bind failed:" << mysql_stmt_error(stmt_handle) << endl; mysql_stmt_close(stmt_handle); return -1; } mysql_return_code = mysql_stmt_execute(stmt_handle); if (0 != mysql_return_code) { cerr << "stmt execute failed:" << mysql_stmt_error(stmt_handle) << endl; mysql_stmt_close(stmt_handle); return -1; } char property_value[256] = {'\0'}; MYSQL_BIND result_var[1]; unsigned long result_var_length[1]; my_bool is_null[1]; bzero(result_var, sizeof(result_var)); result_var[0].buffer_type = MYSQL_TYPE_VAR_STRING; result_var[0].buffer = (char *)property_value; result_var[0].buffer_length = sizeof(property_value)-1; result_var[0].is_null = &is_null[0]; result_var[0].length = &result_var_length[0]; mysql_return_code = mysql_stmt_bind_result(stmt_handle, result_var); if (0 != mysql_return_code) { cerr << "stmt bind rslt failed:" << mysql_stmt_error(stmt_handle) << endl; mysql_stmt_close(stmt_handle); return -1; } mysql_return_code = mysql_stmt_store_result(stmt_handle); if (0 != mysql_return_code) { cerr << "stmt store rslt failed:" << mysql_stmt_error(stmt_handle) << endl; mysql_stmt_close(stmt_handle); return -1; } mysql_return_code = mysql_stmt_fetch(stmt_handle); if (0 != mysql_return_code && MYSQL_NO_DATA != mysql_return_code) { cerr << "stmt fetch failed:" << mysql_stmt_error(stmt_handle) << endl; mysql_stmt_free_result(stmt_handle); mysql_stmt_close(stmt_handle); return -1; } if (MYSQL_NO_DATA != mysql_return_code) { cout << "stmt - got: " << property_value << endl; } mysql_stmt_free_result(stmt_handle); mysql_stmt_close(stmt_handle); mysql_close(connection); mysql_server_end(); cout << "done" << endl; return 0; } Note, that the sample is still wrong, as either buffer_length or length should reflect real lengths of values, not lengths of buffers. kostja@oak:~/work/mysql-4.1-5254/tests> g++ 5254.cc -I../include -L../libmysql/.libs/ -lmysqlclient -lz kostja@oak:~/work/mysql-4.1-5254/tests> ./5254 start up done kostja@oak:~/work/mysql-4.1-5254/tests>