You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用MariaDB C API获取未知结构的预编译语句结果集?

使用MariaDB C API动态遍历预编译语句的结果集

针对你需要动态处理未知结构结果集的场景,核心是利用结果集元数据(metadata)获取列信息,再通过动态绑定缓冲区的方式获取每列的数据。以下是具体实现步骤和示例代码:

核心步骤

  1. 获取结果集元数据:执行预编译语句后,调用mysql_stmt_result_metadata()拿到包含列结构的MYSQL_RES对象。
  2. 遍历列信息:用mysql_num_fields()获取总列数,循环调用mysql_fetch_field_direct()获取每一列的类型、名称等元数据。
  3. 动态分配绑定结构:为每列创建MYSQL_BIND结构体,根据列类型设置对应缓冲区类型,分配足够内存存储数据。
  4. 绑定结果集:调用mysql_stmt_bind_result()将绑定结构与语句关联。
  5. 逐行读取数据:通过mysql_stmt_fetch()循环读取每一行,直接访问MYSQL_BIND中的buffer指针获取底层数据。

示例代码

#include <mysql.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
    MYSQL *conn;
    MYSQL_STMT *stmt;
    MYSQL_RES *meta_result;
    MYSQL_FIELD *field;
    MYSQL_BIND *bind = NULL;
    unsigned int num_fields;
    int i, ret;

    // 初始化并连接数据库(需自行替换连接参数)
    conn = mysql_init(NULL);
    if (!mysql_real_connect(conn, "localhost", "your_user", "your_pass", "your_db", 0, NULL, 0)) {
        fprintf(stderr, "%s\n", mysql_error(conn));
        exit(1);
    }

    // 初始化预编译语句
    stmt = mysql_stmt_init(conn);
    const char *query = "SELECT * FROM your_table WHERE id > ?";
    if (mysql_stmt_prepare(stmt, query, strlen(query)) != 0) {
        fprintf(stderr, "Prepare failed: %s\n", mysql_stmt_error(stmt));
        goto cleanup;
    }

    // 绑定查询参数(示例绑定int类型参数)
    int param_id = 10;
    MYSQL_BIND param_bind;
    memset(&param_bind, 0, sizeof(MYSQL_BIND));
    param_bind.buffer_type = MYSQL_TYPE_LONG;
    param_bind.buffer = &param_id;
    if (mysql_stmt_bind_param(stmt, &param_bind) != 0) {
        fprintf(stderr, "Bind param failed: %s\n", mysql_stmt_error(stmt));
        goto cleanup;
    }

    // 执行预编译语句
    if (mysql_stmt_execute(stmt) != 0) {
        fprintf(stderr, "Execute failed: %s\n", mysql_stmt_error(stmt));
        goto cleanup;
    }

    // 获取结果集元数据
    meta_result = mysql_stmt_result_metadata(stmt);
    if (!meta_result) {
        fprintf(stderr, "Metadata failed: %s\n", mysql_stmt_error(stmt));
        goto cleanup;
    }

    // 获取列总数
    num_fields = mysql_num_fields(meta_result);

    // 分配绑定结构数组
    bind = (MYSQL_BIND *)malloc(sizeof(MYSQL_BIND) * num_fields);
    if (!bind) {
        fprintf(stderr, "Out of memory\n");
        goto cleanup;
    }
    memset(bind, 0, sizeof(MYSQL_BIND) * num_fields);

    // 为每列配置绑定参数
    for (i = 0; i < num_fields; i++) {
        field = mysql_fetch_field_direct(meta_result, i);
        // 根据列类型分配缓冲区并设置类型
        switch (field->type) {
            case MYSQL_TYPE_TINY:
                bind[i].buffer_type = MYSQL_TYPE_TINY;
                bind[i].buffer = malloc(sizeof(char));
                break;
            case MYSQL_TYPE_SHORT:
                bind[i].buffer_type = MYSQL_TYPE_SHORT;
                bind[i].buffer = malloc(sizeof(short));
                break;
            case MYSQL_TYPE_LONG:
                bind[i].buffer_type = MYSQL_TYPE_LONG;
                bind[i].buffer = malloc(sizeof(int));
                break;
            case MYSQL_TYPE_FLOAT:
                bind[i].buffer_type = MYSQL_TYPE_FLOAT;
                bind[i].buffer = malloc(sizeof(float));
                break;
            case MYSQL_TYPE_DOUBLE:
                bind[i].buffer_type = MYSQL_TYPE_DOUBLE;
                bind[i].buffer = malloc(sizeof(double));
                break;
            case MYSQL_TYPE_STRING:
            case MYSQL_TYPE_VAR_STRING:
                bind[i].buffer_type = MYSQL_TYPE_STRING;
                bind[i].buffer = malloc(field->max_length + 1);
                bind[i].buffer_length = field->max_length + 1;
                break;
            default:
                fprintf(stderr, "Unsupported field type: %d\n", field->type);
                goto cleanup;
        }
        // 分配存储数据长度和NULL标识的内存
        bind[i].length = malloc(sizeof(unsigned long));
        bind[i].is_null = malloc(sizeof(my_bool));
    }

    // 绑定结果集到语句
    if (mysql_stmt_bind_result(stmt, bind) != 0) {
        fprintf(stderr, "Bind result failed: %s\n", mysql_stmt_error(stmt));
        goto cleanup;
    }

    // 逐行读取并输出数据
    while ((ret = mysql_stmt_fetch(stmt)) == 0) {
        printf("Row:\n");
        for (i = 0; i < num_fields; i++) {
            field = mysql_fetch_field_direct(meta_result, i);
            printf("  %s (type: %d): ", field->name, field->type);
            if (*bind[i].is_null) {
                printf("NULL\n");
                continue;
            }
            // 根据列类型输出对应数据
            switch (field->type) {
                case MYSQL_TYPE_TINY:
                    printf("%d\n", *(char *)bind[i].buffer);
                    break;
                case MYSQL_TYPE_SHORT:
                    printf("%d\n", *(short *)bind[i].buffer);
                    break;
                case MYSQL_TYPE_LONG:
                    printf("%d\n", *(int *)bind[i].buffer);
                    break;
                case MYSQL_TYPE_FLOAT:
                    printf("%f\n", *(float *)bind[i].buffer);
                    break;
                case MYSQL_TYPE_DOUBLE:
                    printf("%lf\n", *(double *)bind[i].buffer);
                    break;
                case MYSQL_TYPE_STRING:
                case MYSQL_TYPE_VAR_STRING:
                    printf("%.*s\n", (int)*bind[i].length, (char *)bind[i].buffer);
                    break;
            }
        }
    }

    if (ret != MYSQL_NO_DATA) {
        fprintf(stderr, "Fetch failed: %s\n", mysql_stmt_error(stmt));
    }

cleanup:
    // 释放所有分配的资源
    if (bind) {
        for (i = 0; i < num_fields; i++) {
            if (bind[i].buffer) free(bind[i].buffer);
            if (bind[i].length) free(bind[i].length);
            if (bind[i].is_null) free(bind[i].is_null);
        }
        free(bind);
    }
    if (meta_result) mysql_free_result(meta_result);
    if (stmt) mysql_stmt_close(stmt);
    if (conn) mysql_close(conn);
    return 0;
}

关键说明

  • 元数据作用:mysql_stmt_result_metadata()返回的MYSQL_RES对象,即使结果集为空也能提供完整的列结构信息,是动态处理的核心。
  • 数据指针访问:MYSQL_BIND的buffer字段就是底层数据的指针,只需根据列类型做对应类型转换即可读取数据。
  • 内存管理:必须为每个MYSQL_BIND的buffer、length、is_null分配内存,使用完毕后逐一释放,避免内存泄漏。
  • 类型扩展:示例仅覆盖常见类型,你可以根据需求添加其他类型(如日期、二进制数据)的处理逻辑。

内容的提问来源于stack exchange,提问作者Gustavo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 22:35:42