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

如何使用C语言的mysql_connector执行SQL文件?

解决C语言执行MySQL多语句SQL文件的问题

问题场景

尝试用C语言连接MySQL服务器执行SQL文件,最初用mysql_query(conn, "source path/to/file.sql")发现MySQL连接器不支持该命令,于是将SQL文件内容读取到缓冲区后传入mysql_query()执行,但出现语法错误:

Connected.
Error : mysql_query() failed : You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'CREATE DATABASE vacance;

USE vacance;

CREATE TABLE Village (
    CodeVillage i' at line 3
Exit with failure

对应的SQL文件内容:

DROP DATABASE IF EXISTS vacance;

CREATE DATABASE vacance;

USE vacance;

CREATE TABLE Village (
    CodeVillage int,
    NomVillage varchar(30),
    Situation varchar(30)
);

错误原因

  1. mysql_query默认不支持多语句执行:默认情况下,mysql_query()一次只能执行单条SQL语句,而SQL文件包含多条以分号分隔的语句,直接传入会触发语法错误。
  2. 字符串终止符缺失:calloc(sql_file_sz, sizeof(char))分配的空间刚好等于文件大小,没有预留存储字符串结束符'\0'的位置,可能导致MySQL客户端解析时读取到额外垃圾数据。
  3. USE语句的上下文问题:即使开启多语句支持,USE语句切换数据库后,后续语句的执行上下文可能出现异常。

解决方案

1. 开启多语句支持

在调用mysql_real_connect()时,添加CLIENT_MULTI_STATEMENTS标志,允许一次执行多条SQL语句:

if (!mysql_real_connect(conn, host, username, passwd, database, 0, NULL, CLIENT_MULTI_STATEMENTS)) {
    fprintf(stderr, "Error : mysql_real_connect() failed\n");
    goto FatalError;
}

2. 修正文件读取逻辑

分配缓冲区时多预留1字节存储'\0',确保字符串正确终止:

sql_file = (char *)calloc(sql_file_sz + 1, sizeof(char));

3. 处理多语句执行后的结果

执行多语句后,必须调用mysql_next_result()遍历所有语句的执行结果,否则连接会处于异常状态:

if (mysql_query(conn, sql_file) != 0)
{
    fprintf(stderr, "Error : mysql_query() failed : %s\n", mysql_error(conn));
    goto FatalError;
}

// 遍历所有多语句的执行结果
int status;
do {
    status = mysql_next_result(conn);
    if (status > 0) {
        fprintf(stderr, "Error in multi-statement execution: %s\n", mysql_error(conn));
        goto FatalError;
    }
} while (status == 0);

4. 优化SQL语句(可选)

将SQL文件中的USE vacance;替换为在CREATE TABLE时指定数据库名,避免切换数据库的上下文问题:

DROP DATABASE IF EXISTS vacance;

CREATE DATABASE vacance;

CREATE TABLE vacance.Village (
    CodeVillage int,
    NomVillage varchar(30),
    Situation varchar(30)
);

修改后的完整代码

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

size_t get_file_size(char *path);

int main() {

    /* Declaration */

    MYSQL *conn;
    char username[] = "user";
    char passwd[] = "user";
    char host[] = "localhost";
    char database[] = "";
    char sql_file_path[] = "./db.sql";
    char *sql_file;
    size_t sql_file_sz;
    FILE *sql_fs;

    /* Initialisation */

    sql_file_sz = get_file_size(sql_file_path);
    // 多分配1字节存储'\0'
    sql_file = (char *)calloc(sql_file_sz + 1, sizeof(char));
    sql_fs = fopen(sql_file_path, "r");
    if (!sql_fs)
    {
        perror("Error : ");
        goto FatalError;
    }
    fread(sql_file, sql_file_sz, 1, sql_fs);
    if (ferror(sql_fs))
    {
        perror("Error : ");
        goto FatalError;
    }

    conn = mysql_init(NULL);
    
    if (conn == NULL) {
        fprintf(stderr, "Error : mysql_init() failed\n");
        goto FatalError;
    }
    
    // 连接时开启多语句支持
    if (!mysql_real_connect(conn, host, username, passwd, database, 0, NULL, CLIENT_MULTI_STATEMENTS)) {
        fprintf(stderr, "Error : mysql_real_connect() failed\n");
        goto FatalError;
    }
    printf("Connected.\n");

    if (mysql_query(conn, sql_file) != 0)
    {
        fprintf(stderr, "Error : mysql_query() failed : %s\n", mysql_error(conn));
        goto FatalError;
    }

    // 遍历所有多语句的执行结果
    int status;
    do {
        status = mysql_next_result(conn);
        if (status > 0) {
            fprintf(stderr, "Error in multi-statement execution: %s\n", mysql_error(conn));
            goto FatalError;
        }
    } while (status == 0);

    /* Leaving */

    mysql_close(conn);
    fclose(sql_fs);
    free(sql_file);
    
    printf("Exit success.\n");
    return EXIT_SUCCESS;

FatalError:

    if (conn)
        mysql_close(conn);
    if (sql_fs)
        fclose(sql_fs);
    if (sql_file)
        free(sql_file);

    printf("Exit with failure.\n");
    return EXIT_FAILURE;
}

/* 
    Return file size.

    On error, return -1;
*/
size_t get_file_size(char *path)
{
    size_t sz;
    FILE *fp;
    
    fp = fopen(path, "r");
    if (!fp)
    {
        perror("Error : ");
        return -1;
    }

    fseek(fp, 0L, SEEK_END);
    sz = ftell(fp);
    rewind(fp);

    fclose(fp);

    return sz;
}

验证结果

修改后重新编译执行代码,会输出:

Connected.
Exit success.

登录MySQL客户端可确认数据库vacance和表Village已成功创建。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 21:55:00