MariaDB Connector/C预处理语句传字符串查询返回空结果问题
问题:MariaDB Connector/C 预处理语句传递字符串参数无查询返回结果
使用MariaDB Connector/C完成课程作业的数据库操作时,预处理语句传递字符串参数查询无匹配结果,已排查2天临近提交截止日,相关信息如下:
测试基础信息
- 测试表
t3数据:
执行查询SQL:
SELECT * FROM t3;
返回结果:
| a | b |
|---|---|
| 0 | abc |
| 1 | bcd |
| 2 | af |
3 rows in set Time: 0.010s
- 测试表结构:
执行结构查询SQL:
DESC t3;
返回结果:
| Field | Type | Null | Key | Default | Extra |
|---|---|---|---|---|---|
| a | int(11) | NO | PRI | ||
| b | char(10) | YES |
2 rows in set Time: 0.011s
测试用C语言代码
#include <mysql/mysql.h> #include <stdio.h> #include <stdlib.h> #include <string.h> int main() { MYSQL *mysql; mysql = mysql_init(NULL); if (!mysql_real_connect(mysql,NULL , "none", "linux", "test", 0,"/tmp/mariadb.sock",0)){ printf( "Error connecting to database: %s",mysql_error(mysql)); } else printf("Connected...\n"); if(mysql_real_query(mysql,"SET CHARACTER SET utf8",(unsigned int)sizeof("SET CHARACTER SET utf8"))){ printf("Failed to set Encode!\n"); } char query_stmt_2[]="select * from t3 where b=?"; MYSQL_STMT *stmt2 = mysql_stmt_init(mysql); if(mysql_stmt_prepare(stmt2, query_stmt_2, -1)) { printf("STMT2 prepare failed.\n"); } MYSQL_BIND instr_bind; char instr[50]="abc"; my_bool in_is_null = 0; my_bool in_error = 0; instr_bind.buffer_type = MYSQL_TYPE_STRING; instr_bind.buffer = &instr[0]; char in_ind = STMT_INDICATOR_NTS; instr_bind.u.indicator = &in_ind; unsigned long instr_len=sizeof(instr); // instr_bind.length = &instr_len; // instr_bind.buffer_length=instr_len; instr_bind.is_null = &in_is_null; instr_bind.error = &in_error; MYSQL_BIND out_bind[2]; memset(out_bind, 0, sizeof(out_bind)); int out_int[2]; char outstr[50]; my_bool out_int_is_null[2]={0,0}; my_bool out_int_error[2]={0,0}; unsigned long out_int_length[2]={0,0}; out_bind[0].buffer = out_int+0; out_bind[0].buffer_type = MYSQL_TYPE_LONG; out_bind[0].is_null = out_int_is_null+0; out_bind[0].error = out_int_error+0; out_bind[0].length = out_int_length+0; out_bind[1].buffer = outstr; out_bind[1].buffer_type = MYSQL_TYPE_STRING; out_bind[1].buffer_length = 50; out_bind[1].is_null = out_int_is_null+1; out_bind[1].error = out_int_error+1; out_bind[1].length = out_int_length+1; if(mysql_stmt_bind_param(stmt2, &instr_bind) || mysql_stmt_bind_result(stmt2, out_bind)){ printf("Bind error\n"); } if(mysql_stmt_execute(stmt2)) { printf("Exec error: %s",mysql_stmt_error(stmt2)); } if(mysql_stmt_store_result(stmt2)){ printf("Store result error!\n"); printf("%s\n",mysql_stmt_error(stmt2)); } while(!mysql_stmt_fetch(stmt2)) { printf("%d\t%s\n", out_int[0], outstr); } mysql_stmt_close(stmt2); end: mysql_close(mysql); }
运行现象
程序执行后仅输出数据库连接成功提示,无任何查询结果返回,运行输出如下:
❯ ./Exec/test/stmt_test Connected...
问题原因与修复方案
代码核心问题出在输入参数MYSQL_BIND的配置错误,具体有两点:
STMT_INDICATOR_NTS指示器使用不规范
你使用STMT_INDICATOR_NTS标识传入字符串为'\0'结尾的空终止字符串,期望驱动自动计算长度,但未给instr_bind设置buffer_length字段,旧版本MariaDB Connector/C会读取该字段未初始化的脏值作为参数长度,导致传给数据库的参数内容异常,无法匹配到b='abc'的记录。- 输入参数绑定结构体未初始化
定义MYSQL_BIND instr_bind时未做清零操作,结构体中未手动赋值的字段为栈上随机脏值,会直接干扰预处理语句的参数解析逻辑。
额外注意:你代码中写的unsigned long instr_len=sizeof(instr);也存在错误,sizeof(instr)获取的是char[50]数组的总长度50,而非存储的字符串"abc"的实际长度3,就算其他配置正确,这里如果用sizeof计算长度,也会把数组后续的栈内存脏值作为参数内容传给数据库,同样无法匹配到正确结果。
修复代码
将输入参数绑定部分替换为以下内容即可:
MYSQL_BIND instr_bind; // 先清零结构体,避免脏值干扰 memset(&instr_bind, 0, sizeof(instr_bind)); char instr[50]="abc"; my_bool in_is_null = 0; my_bool in_error = 0; instr_bind.buffer_type = MYSQL_TYPE_STRING; instr_bind.buffer = instr; // 手动指定字符串实际长度,兼容性最好 unsigned long instr_len = strlen(instr); instr_bind.length = &instr_len; instr_bind.buffer_length = sizeof(instr); instr_bind.is_null = &in_is_null; instr_bind.error = &in_error;
修改后重新编译运行,即可正常返回0 abc的查询结果。
内容的提问来源于stack exchange,提问作者pb_wang
相关产品推荐
相关产品推荐

