我的 C 程序如何将字符串插入到包含字符> 0x80的 mariadb 数据库中

How does my C program insert a string into a mariadb database which contains a character > 0x80

提问人:Dave Coventry 提问时间:5/14/2023 最后编辑:Dave Coventry 更新时间:5/19/2023 访问量:101

问:

我的 C 程序尝试将字符串插入 Mariadb 数据库:

sprintf(query,"INSERT INTO text(drawing, eID, txt) VALUES(%s,%ld,'%s');",drawing_number,element_handle,txt);
mysql_query(sqlconnect,query);

如果 txt 字符串不包含字符 > 127,则它可以正常工作。

但是,如果字符串包含度数字符,例如(°,0xB0),则据我所知,该字符串不会插入到数据库中,而不会出现任何错误。

GDB 显示已正确提交字符串的查询,但未包含以下字符:

(GDB) P 查询

$7 = 0x5555555a1dd0 “INSERT INTO text(drawing, eID, txt) VALUES(6,1000699,'FOR DETAILS OF');”

但是对于包含度数字符的字符串,这是 GDB 向我展示的:

(GDB) P 查询

$8 = 0x5555555a1dd0 “INSERT INTO text(drawing, eID, txt) VALUES(6,1000700,'SUCTION BOX 22\260');”

如果我使用“”或“”搜索数据库,它将返回一个空集。select * from text where drawing=6 and txt like 'SUCTION BOX%';select * from text where drawing=6 and eID=1000700;

数据库架构为“utf8mb3”。

显然,字符串的编码不正确,那么如何确保它编码正确?

这不可能是一个独特的问题,但我似乎找不到解决方案(很可能我使用了糟糕的搜索字符串),所以我希望你能原谅重复。

建议的解决方案似乎是使用 C 查询具有 unicode 字符的数据库。据我所知,该行实际上并没有首先插入到数据库中。我可以手动插入行:。INSERT INTO text(drawing, eID, txt) VALUES(6,1000700,'SUCTION BOX 22�');

它显然不是由我的编译器编码的。gcc 版本 11.3.0 (Ubuntu 11.3.0-1ubuntu1~22.04)。

我的研究表明,默认情况下,char 数据类型会自动指定为 utf8。我假设是这样吗?

原始文本采用固定的宽字符格式,即两个字节,最低有效字节在前。不过,我不认为这是一种正常的 wc 格式,因为我尝试使用 wctombs() 失败了。

C UTF-8 玛丽亚德

评论

1赞 Tom Karzes 5/14/2023
UTF-8 需要多个字节来编码非 ASCII 字符,例如度数符号。您可能需要将非 ASCII 字符编码为正确的 UTF-8 序列。
1赞 Ruud Helderman 5/14/2023
这回答了你的问题吗?MySQL 连接器 C/C API - 使用特殊字符进行查询
0赞 Georg Richter 5/14/2023
您没有设置客户端字符集
1赞 Bill Karwin 5/15/2023
您还应该使用绑定参数而不是 .在此处查看 MariaDB C API 的完整示例:mariadb.com/kb/en/bulk-insert-column-wise-bindingsprintf()
1赞 Rick James 5/15/2023
对于拉丁语 1,度数符号为十六进制 B0。对于 utf8,它是十六进制 C2B0。您必须在配置中或连接期间指定客户端的编码。(这就是问题所在。

答:

0赞 Dave Coventry 5/19/2023 #1

该问题是导致 utf-8 字符数组被错误分配。

我创建了一个 wchar_t 数组,并用原始数组填充它(它由 2 个字节组成,最低有效字节在前)。

   for(int i=0;i<sz;i++){
     ut[i]=(s[ii++])&0xFF;
     ut[i]+=((s[ii]&0xFF)<<8);
     ut[i]&=0xFFFF;
     ii++;
     if(!ut[i])
       break;
   }

然后,我将新创建的数组转换为字符。wctombs

  char *rt;
  rt=(char *)malloc(sz*2);
  wcstombs(rt,ut,sz);
  return rt;

这奏效了。

我不知道为什么,但是原始数组的格式与转换工具不兼容。

我相信有更好的方法,并且会坦率地承认我的编码非常笨拙,但我想结束这个问题。

非常感谢所有回复的人。