如何在mysqlclient (C库)中处理(转义)%符号


How to Handle (Escape) a % sign in mysqlclient (C Library)

我正在使用mysqlclient,

在我的一个查询中,如下所示

sprintf (query, "select user from pcloud_session where id = '%s'", sid);

在这里,有时这个边带有%符号,就像例子

2Cq%yo4i-ZrizGGQGQ71eJQ0

但是当有这个%时,这个查询总是失败,我想我必须转义这个%,但是怎么转义呢?

我尝试了'和%%,但这两个都不工作,请帮助我这里

更新:

使用session时。hash_bits_per_character = 6,在php会话中,默认的字符集包含一个字符(逗号),该字符将始终被urlencoded(这里是%2C)。这导致cookie值中有%2C,但会话数据库中有一个逗号代替它。有什么办法解决这个问题吗?很抱歉造成混乱

谢谢

MySQL查询文本中不需要转义文字'%'

当你说查询"总是失败",它是调用mysql_query函数返回一个错误吗?它是否返回SQL异常代码,或者它只是不返回您期望的结果集(行)?

为了调试,我建议在调用sprintf后,回显query字符串的内容。我们期望字符串的内容是:

select user from pcloud_session where id = '2Cq%yo4i-ZrizGGQGQ71eJQ0'

和我没有看到任何错误的SQL结构(假设id列存在于pcloud_session和字符数据类型。即使id被定义为整数类型,该语句通常也不会抛出异常,字符串字面值只会被解释为2的整数值。

在sprint的目标格式中包含'%'字面值应该没有问题。在MySQL查询文本中包含'%'文字应该没有问题。

(当然,我假设sid是由对mysql_real_escape_string函数的调用填充的)


再次,我建议您在调用sprintf之后回显query的内容。我还建议您确保没有其他代码与该字符串的内容混淆,这是作为参数传递给mysql_query函数的实际字符串。(如果您使用的是mysql_real_query函数,那么请确保您传递的长度是正确的。)


更新

Oxi说:"它没有返回SQL异常代码,它只是没有返回我期望的结果[集]。"我确实打印了查询,它打印了%。"

@ ox

这里有一大堆问题可以帮助你找到问题。

您是否从mysql命令行客户端运行该查询文本的测试,并且返回您期望的行?

id列定义为VARCHAR(或CHAR)的长度(至少)24个字符?列上的排序设置为不区分大小写还是区分大小写?

show create table pcloud_session ;

(我没有看到任何会导致字符集转换问题的字符,尽管如果应用程序不匹配数据库字符集编码,这可能是问题的根源。)

您是否对id列使用LIKE谓词测试过查询?

SELECT id, user FROM pcloud_session WHERE id LIKE '2Cq'%yo4i-%' ESCAPE ''''
 ORDER BY id LIMIT 10 ;
SELECT id, user FROM pcloud_session WHERE id LIKE '2Cq%'
 ORDER BY id LIMIT 10 ;

当您期望一行时,您是否没有返回行?返回的行是否太多,或者得到的行是否与预期的行不同?

对于id列来说,这是一个奇怪的值。起初,它看起来几乎像是用base-64编码表示的值,但它不是任何标准编码,因为它包含'%'和'-'字符。

如果您打算在没有接口库的情况下在C中执行此操作,则必须使用mysql_real_escape_string来执行正确的SQL转义。

在MySQL内部使用'% inside of a string, though, as the only context in which it has meaning is either directly in printf type functions or as an argument to LIKE '不应该有任何本质上的错误。

这被证明是非常烦人的,但这是绝对必要的。这将使你的代码更加复杂,这就是为什么在C中使用低级MySQL通常是一个坏主意。c++包装器将为您提供更多的支持。

您真的不应该自己转义字符串。最安全的选择是让MySQL API为你处理它。

对于最大长度为n的字符串,首先分配一个长度为2*n+1的字符串:

int sidLength = strlen(sid);
// worst-case, we need to escape every character, plus a byte for the ASCIIZ
int maxSafeSidLength = sidLength * 2 + 1;
char *safeSid = malloc(maxSafeSidLength);
// copy "sid" to "safeSid", escaping as appropriate
mysql_real_escape_string(mysql, safeSid, sid, sidLength);

// build the query
// ...
free(safeSid);

在dev.mysql.com的mysql_real_escape_string页面上有一个更长的例子,其中他们构建了整个查询字符串,但上述方法应该适用于为sprintf提供safeSid。