【问题标题】:C API Support for calling mysql stored procedureC API 支持调用mysql存储过程
【发布时间】:2016-07-08 22:27:11
【问题描述】:

我正在开发一个与 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 参数则不行。

link 链接中提到的 varchar 输入参数类型是 MYSQL_TYPE_STRING,输出参数类型是 MYSQL_TYPE_VAR_STRING

问题: 得到空的结果。 据我分析,status = mysql_stmt_fetch(stmt);函数通过表中存在的条目返回 100(MYSQL_NO_DATA)。

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

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

有人帮我把这个短路吗?

【问题讨论】:

  • 您确定在 varchar ps_params 的情况下应该采用指向 char 的指针而不是指向 char 的指针吗?您是否尝试过以下操作:const char * x = &amp;(input_buf[0]); ps_params[0] = (void *)&amp;x;
  • 感谢回复。我试过 (void*)&x;但它仍然保持不变@MysticOdin
  • 这是正确的做法吗?或者我可以使用任何其他方法来实现这一点吗?
  • 我将过程更改为 INSERT 而不是 SELECT。它工作正常。如果查询包含 '=' 运算符,例如 'where' ,则 'set' 会产生空值。任何人都知道如何使用 C API 在哪里进行选择

标签: mysql c stored-procedures


【解决方案1】:

为了设置一个 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);

希望对你有帮助

【讨论】:

  • 欢迎来到SO,请解释你的答案并格式化你的代码sn-ps。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-03-02
  • 2012-06-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-23
  • 2016-05-03
相关资源
最近更新 更多