从mariadb客户端调用Mysql 5.6存储过程

时间:2014-01-30 11:15:17

标签: c++ mysql c client mariadb

您好我已经编写了一些使用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;
}

0 个答案:

没有答案