C API支持调用mysql存储过程

时间:2016-03-22 06:26:11

标签: mysql c stored-procedures

我正在开发一个与mysql交互的C项目。所以我打算使用mysql存储过程并在此link中找到一个示例程序 我刚刚根据项目的要求改变了程序。这是表结构

 id             | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
username        | varchar(64)      | NO   | MUL | NULL    |                |
password        | varchar(25)      | NO   |     | NULL    |                |

这是我的计划。

 int main()
{
    MYSQL_RES *result;
    MYSQL *mysql=mysql_init(NULL);

    /* connect to server with the CLIENT_MULTI_STATEMENTS option */
    if (mysql_real_connect (mysql, "localhost", "root", "root123","DONT_USE", 0, NULL , CLIENT_MULTI_STATEMENTS) == NULL)
    {
            printf("mysql_real_connect() failed\n");
            mysql_close(mysql);
    }


    MYSQL_STMT *stmt;
    MYSQL_BIND ps_params[1];  /* input parameter buffers */
    long int        int_data[3];   /* input/output values */
    my_bool    is_null[3];    /* output value nullability */
    int        status;
    char own_buf[25],input_buf[64];
    memset(own_buf, 0, 25);
    memset(input_buf, 0, 64);

    /* set up stored procedure */
    status = mysql_query(mysql, "DROP PROCEDURE IF EXISTS p1");
    test_error(mysql, status);

    status = mysql_query(mysql,
              "CREATE PROCEDURE p1("
              "  IN p_in VARCHAR(64)) "
              "BEGIN "
              "  SELECT password from data where username=p_in; "
              "END");
    test_error(mysql, status);

    /* initialize and prepare CALL statement with parameter placeholders */
    stmt = mysql_stmt_init(mysql);
    if (!stmt)
    {
            printf("Could not initialize statement\n");
    }
    status = mysql_stmt_prepare(stmt, "CALL p1(?)", 10);
    test_stmt_error(stmt, status);

    /* initialize parameters: p_in, p_out, p_inout (all INT) */
    memset(ps_params, 0, sizeof (ps_params));

    ps_params[0].buffer_type = MYSQL_TYPE_STRING;
    ps_params[0].buffer = (void *) &input_buf;
    ps_params[0].buffer_length = sizeof(input_buf);
    ps_params[0].is_null = 0;

    /* bind parameters */
    status = mysql_stmt_bind_param(stmt, ps_params);
    test_stmt_error(stmt, status);

    /* assign values to parameters and execute statement */
    int_data[0]= 2;  /* p_in */
    int_data[1]= 20;  /* p_out */

    strcpy(input_buf,"'6666600222'");
    int_data[0] = strlen(input_buf);
    input_buf[int_data[0]] = '\0';
    ps_params[0].length = &int_data[0];


    status = mysql_stmt_execute(stmt);
    test_stmt_error(stmt, status);

    /* process results until there are no more */
    do {
            int i;
            int num_fields;       /* number of columns in result */
            MYSQL_FIELD *fields;  /* for result set metadata */
            MYSQL_BIND *rs_bind;  /* for output buffers */

            /* the column count is > 0 if there is a result set */
            /* 0 if the result is only the final status packet */
            num_fields = mysql_stmt_field_count(stmt);

            if (num_fields > 0)
            {
                    /* there is a result set to fetch */
                    printf("Number of columns in result: %d\n", (int) num_fields);

                    /* what kind of result set is this? */
                    printf("Data: ");
                    if(mysql->server_status & SERVER_PS_OUT_PARAMS)
                            printf("this result set contains OUT/INOUT parameters\n");
                    else
                            printf("this result set is produced by the procedure\n");

              MYSQL_RES *rs_metadata = mysql_stmt_result_metadata(stmt);
              test_stmt_error(stmt, rs_metadata == NULL);

              fields = mysql_fetch_fields(rs_metadata);

              rs_bind = (MYSQL_BIND *) malloc(sizeof (MYSQL_BIND) * num_fields);
                    if (!rs_bind)
                    {
                            printf("Cannot allocate output buffers\n");
                    }
                    memset(rs_bind, 0, sizeof (MYSQL_BIND) * num_fields);

                    /* set up and bind result set output buffers */
                    for (i = 0; i < num_fields; ++i)
                    {
                            rs_bind[i].buffer_type = fields[i].type;
                            rs_bind[i].is_null = &is_null[i];

                            switch (fields[i].type)
                            {
                                    case MYSQL_TYPE_LONG:
                                            rs_bind[i].buffer = (char *) &(int_data[i]);
                                            rs_bind[i].buffer_length = sizeof (int_data);
                                            break;
                                    case MYSQL_TYPE_VAR_STRING:
                                            rs_bind[i].buffer = (char *) own_buf;
                                            rs_bind[i].buffer_length = sizeof(own_buf);
                                            rs_bind[i].length = &int_data[1];
                                            break;

                                    default:
                                            fprintf(stderr, "ERROR: unexpected type: %d.\n", fields[i].type);
                            }
                    }

                    status = mysql_stmt_bind_result(stmt, rs_bind);
                    test_stmt_error(stmt, status);

                    /* fetch and display result set rows */
                    while (1)
                    {
                            status = mysql_stmt_fetch(stmt);

                            if (status == 1 || status == MYSQL_NO_DATA)
                                    break;

                            for (i = 0; i < num_fields; ++i)
                            {
                                    switch (rs_bind[i].buffer_type)
                                    {
                                            case MYSQL_TYPE_LONG:
                                                    if (*rs_bind[i].is_null)
                                                            printf(" val[%d] = NULL;", i);
                                                    else
                                                            printf(" val[%d] = %ld;",
                                                                            i, (long) *((int *) rs_bind[i].buffer));
                                                    break;
                                            case MYSQL_TYPE_VAR_STRING:
                                                    printf(" val[%d] = %s;",i,(char*)rs_bind[i].buffer);
                                                    break;

                                            default:
                                                    printf("  unexpected type (%d)\n",
                                                                    rs_bind[i].buffer_type);
                                    }
                            }
                            printf("\n");
                    }

                    mysql_free_result(rs_metadata); /* free metadata */
                    free(rs_bind);                  /* free output buffers */
            }
            else
            {
                    /* no columns = final status packet */
                    printf("End of procedure output\n");
            }

            /* more results? -1 = no, >0 = error, 0 = yes (keep looking) */
            status = mysql_stmt_next_result(stmt);
            if (status > 0)
                    test_stmt_error(stmt, status);
    } while (status == 0);

    mysql_stmt_close(stmt);
 }

OUTPUT:
Number of columns in result: 1
Data: this result set is produced by the procedure
End of procedure output

上面的代码在整数参数的情况下工作正常,例如 CREATE PROCEDURE p1(IN p_in INT),但不适用于varchar参数。

varchar输入参数类型的链接中提到的

link是MYSQL_TYPE_STRING,输出参数类型是MYSQL_TYPE_VAR_STRING

问题: 获得空洞的结果。 就我的分析而言,status = mysql_stmt_fetch(stmt);函数通过表中的条目返回100(MYSQL_NO_DATA)。

注意:我尝试将程序手动调用到mysql中,如调用p1(&#39; 6666600222&#39;);结果

mysql> call p1('6666600222');
+----------+
| password |
+----------+
| 1234     |
+----------+
1 row in set (0.00 sec)

有人帮我把它缩短了吗?

1 个答案:

答案 0 :(得分:0)

为了设置varchar参数,ps_params应该将指针指向char而不指向指向char的指针。

尝试更改:

ps_params[0].buffer = (void *) &input_buf;

为:

ps_params[0].buffer = (void *)&(input_buf[0]); // or just (void *)input_buf

设置字符串值到input_buf之后设置ps_params [0] .buffer_length如下:

ps_params[0].buffer_length = strlen(input_buf);

希望这有帮助