您好我已经编写了一些使用MariaDB客户端在MySQL数据库中调用存储过程的代码,但是stmt-> bind参数没有填充必要的MYSQL_BIND数组来接收必要的数据。
我做错了什么或是否有驱动程序错误? Malloc'ing数据不会破坏实现,但MySQL有比malloc更有效的方法来管理这些数组的内存。
如果你在问,我正在使用和滥用switch语句,因为我希望这个函数最终在一个cooroutine functor类中使用一个连接池工作,其中一个状态值用来控制我们在哪里在switch语句中。
//the function that does all the heavy lifting for persistence
xt::data::io::ret_val mysql_model::call_stored_proc(xt::data::model_factory& factory,
const xt::object& obj,
const xt::object* p_prev_obj,
xt::data::io_call_back*& cb,
const char* command)
{
MYSQL *mysql = NULL;
int state = 0;
MYSQL_STMT* stmt = NULL;
int status = 0;
size_t parameter_length = 0;
std::vector<MYSQL_BIND> ps_params;
xt::data::io::ret_val ret = xt::data::io::io_success;
xt::string sql("CALL ");
xt::messaging::event_type type = xt::messaging::new_object;
if(std::strcmp(command, "update") == 0)
{
sql += m_update_proc;
type = xt::messaging::update_object;
}
else if(std::strcmp(command, "delete") == 0)
{
sql += m_delete_proc;
type = xt::messaging::delete_object;
}
else
{
sql += m_insert_proc;
assert(command == "insert");
}
sql += "(?";
for(size_t i = 0;i < m_p_mem_row_set->get_field_handlers().size();i++)
{
sql += ",?";
}
sql += ")";
switch(state)
{
case 0:
mysql= mysql_init(NULL);
if(!mysql_set_server_option(mysql, MYSQL_OPTION_MULTI_STATEMENTS_ON))
{
show_error(mysql);
return xt::data::io::io_exception;
}
if (!mysql_real_connect(mysql, m_server.data(),
m_user_name.data(),
m_password.data(),
m_schema.data(),
0,
NULL,
0))
{
LOG_ERROR3("Could not connect error(%s) [%s] \"%s\"", xt::longToString(mysql_errno(mysql)), mysql_sqlstate(mysql), mysql_error(mysql));
ret = xt::data::io::io_exception;
break;
}
stmt = mysql_stmt_init(mysql);
if(!stmt)
{
LOG_ERROR("Could not initialize statement\n");
ret = xt::data::io::io_exception;
break;
}
stmt->bind = NULL;
if(mysql_stmt_prepare(stmt, sql.data(), (unsigned long)sql.size()))
{
LOG_ERROR3("Could not prepare statement error(%s) [%s] \"%s\"", xt::longToString(mysql_errno(mysql)), mysql_sqlstate(mysql), mysql_error(mysql));
ret = xt::data::io::io_exception;
break;
}
parameter_length = m_p_mem_row_set->get_field_handlers().size() + 2;
ps_params.resize(parameter_length);
{
xt::data::io::ret_val r = prepare_memset(ps_params, m_p_mem_row_set->get_field_handlers(), obj, command);
if(r != xt::data::io::io_success)
{
ret = xt::data::io::io_exception;
break;
}
}
//reuse params so offset from 1
if(mysql_stmt_bind_param(stmt, &ps_params[1]))
{
LOG_ERROR2("Could not bind parameters error: %s (errno: %s)\n", mysql_stmt_error(stmt), xt::longToString(mysql_stmt_errno(stmt)));
ret = xt::data::io::io_exception;
break;
}
status = mysql_stmt_execute(stmt);
if(status)
{
LOG_ERROR2("Could not execute stored procedure error: %s (errno: %s)\n", mysql_stmt_error(stmt), xt::longToString(mysql_stmt_errno(stmt)));
ret = xt::data::io::io_exception;
break;
}
{
/* the column count is > 0 if there is a result set */
/* 0 if the result is only the final status packet */
int num_fields = mysql_stmt_field_count(stmt);
if (num_fields > 0)
{
if(num_fields != parameter_length)
{
LOG_ERROR("parameter fields do not match returned resultset");
ret = xt::data::io::io_exception;
break;
}
//buffer to be a write target
for(size_t i = 0;i < parameter_length;i++)
{
if(ps_params[i].buffer_type == MYSQL_TYPE_STRING || ps_params[i].buffer_type == MYSQL_TYPE_DECIMAL)
{
ps_params[i].buffer = (char *) new char[ps_params[i].buffer_length + 1];
memset(ps_params[i].buffer, 0, ps_params[i].buffer_length + 1);
ps_params[i].length = new unsigned long;
*ps_params[i].length = ps_params[i].buffer_length;
}
}
#pragma message("hack!!!!! bind not being allocated for stored proc")
if (!(stmt->bind= (MYSQL_BIND *)malloc(stmt->field_count * sizeof(MYSQL_BIND))))
{
// SET_CLIENT_STMT_ERROR(stmt, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0);
LOG_ERROR("Out of memory");
ret = xt::data::io::io_exception;
break;
}
status = mysql_stmt_bind_result(stmt, &ps_params[0]);
if(status)
{
LOG_ERROR2("Could not bind results error: %s (errno: %s)\n", mysql_stmt_error(stmt), xt::longToString(mysql_stmt_errno(stmt)));
ret = xt::data::io::io_exception;
break;
}
status = mysql_stmt_fetch(stmt);
if (status == 1 || status == MYSQL_NO_DATA)
{
LOG_ERROR("No data returned from stored proc");
ret = xt::data::io::io_exception;
break;
}
else if(status)
{
LOG_ERROR2("Error on fetching results error: %s (errno: %s)\n", mysql_stmt_error(stmt), xt::longToString(mysql_stmt_errno(stmt)));
ret = xt::data::io::io_exception;
break;
}
else
{
ret = (xt::data::io::ret_val) *((int *) ps_params[0].buffer);
if(ret != xt::data::io::io_success)
{
const char* error_message = ((char *) ps_params[1].buffer);
LOG_ERROR(error_message);
// dont break; we want to clean memory up regardless
}
//now clean up memory
delete ps_params[1].length;
ps_params[1].length = NULL;
delete [] ps_params[1].buffer;
ps_params[1].buffer = NULL;
for (int i = 2; i < parameter_length && ret == xt::data::io::io_success; ++i)
{
rowset_item* item = m_p_mem_row_set->get_field_handlers()[i - 2];
switch (ps_params[i].buffer_type)
{
case MYSQL_TYPE_STRING:
case MYSQL_TYPE_DECIMAL:
if(ret == xt::data::io::io_success)
{
((rowset_item_string_t<char>&)*item).set_data(static_cast<char*>(ps_params[i].buffer), const_cast<xt::object*>(&obj), 0);
}
delete ps_params[i].length;
ps_params[i].length = NULL;
delete [] ps_params[i].buffer;
ps_params[i].buffer = NULL;
break;
case MYSQL_TYPE_DATE:
delete (DATE_STRUCT*)ps_params[i].buffer;
ps_params[i].buffer = NULL;
break;
case MYSQL_TYPE_TIME:
delete (TIME_STRUCT*)ps_params[i].buffer;
ps_params[i].buffer = NULL;
break;
case MYSQL_TYPE_TIMESTAMP:
delete (TIMESTAMP_STRUCT*)ps_params[i].buffer;
ps_params[i].buffer = NULL;
break;
case MYSQL_TYPE_TINY:
case MYSQL_TYPE_SHORT:
case MYSQL_TYPE_LONG:
case MYSQL_TYPE_LONGLONG:
case MYSQL_TYPE_FLOAT:
case MYSQL_TYPE_DOUBLE:
case MYSQL_TYPE_BIT:
break;
case MYSQL_TYPE_BLOB:
case MYSQL_TYPE_VAR_STRING:
default:
LOG_ERROR1("unexpected type (%s)",xt::longToString(ps_params[i].buffer_type));
assert(false);
ret = xt::data::io::io_exception;
break;
}
}
}
}
else
{
LOG_ERROR("no data returned from stored proc");
assert(false);
ret = xt::data::io::io_exception;
break;
}
}
default:
break;
}
if(stmt != NULL)
{
free(stmt->bind);
mysql_stmt_close(stmt);
}
if(mysql != NULL)
{
mysql_close(mysql);
}
cb->on_model_request_complete( ret,
type,
factory,
*this,
obj,
p_prev_obj,
true);
cb = NULL;
return ret;
}