1

中构建 SQL是一项痛苦的工作。构建这样的东西需要很多时间。我是新手。它有助于字符串操作。但我没有找到任何可以缩短查询构建代码的方法。在此处查看示例。

GString *acc_protocol = g_string_new(acc->prpl->name);
GString *acc_handle = g_string_new(acc->user);
GString *acc_password = g_string_new(acc->pass);
GString *acc_tag = g_string_new(acc->tag);
g_string_printf(q, "INSERT INTO accounts (user, protocol, handle, password, autoconnect, tag) values (%ld, ", user_id);
g_string_append(q,"'");
append_mysql_escaped_param(q, buf, acc_protocol);
g_string_append(q,"', '");
append_mysql_escaped_param(q, buf, acc_handle);
g_string_append(q,"', '");
append_mysql_escaped_param(q, buf, acc_password);
g_string_append(q,"', '");
g_string_append(q, atoi(acc->auto_connect));
g_string_append(q,"', '");
append_mysql_escaped_param(q, buf, acc_tag);
g_string_append(q,"') on duplicate key UPDATE password='");
append_mysql_escaped_param(q, buf, acc_password);
g_string_append(q,"', autoconnect='");
g_string_append(q, atoi(acc->auto_connect));
g_string_append(q,"', tag='");
append_mysql_escaped_param(q, buf, acc_tag);
g_string_append(q,"'");

g_string_free(acc_handle);
g_string_free(acc_password);
g_string_free(acc_protocol);
g_string_free(acc_tag);

mysql_real_query(mysql);
    num_rows =  mysql_affected_rows(mysql);
    ....
/// .... mysql processing here ...

为了您的方便,这里是功能append_mysql_escaped_param

static void append_mysql_escaped_param(GString *query, GString *buffer, GString *param){
    g_string_set_size(buffer, param->len*2+1);
    mysql_real_escape_string(mysql, buffer->str, param->str, param->len);
    g_string_append(query, buffer->str);
}

我怎样才能让它变小?这里有太多的冗余代码,足以让人头疼不已。有什么改进的办法吗?

我知道我可以使用准备好的语句。但是当我在准备好的语句上绑定值时,我也需要编写这样的批量代码。我只想摆脱容易出错的冗余代码。这尤其适用于 C。

4

3 回答 3

1

我会推荐g_strdup_printf。这使您可以摆脱与缓冲区相关的怪癖,并启用printf对字符串等的类似用法。您所要做的就是取消分配生成的缓冲区。

为了正确转义,我建议查看g_strcanon,它允许查找和替换字符。

于 2012-07-30T16:30:12.040 回答
1

我只会回答您的最后一个问题(“有什么改进的想法吗?”)。

您在代码中所做的仅适用于某些一次性数据库访问或极不频繁的访问。每次新的请求文本到达数据库服务器时,它与任何缓存的字符串都不匹配,服务器将不得不花费大量时间准备执行语句。准备工作通常会占用查询总执行时间的 50-90%。

现在,我建议您做的改进是将您的数据库访问分为三个阶段:准备、绑定、执行:

  • 准备是您将常量文本字符串发送到带有占位符的数据库服务器的地方,用于将实际值绑定到其中
  • 绑定是您为这些占位符分配值的地方,绑定输入和输出参数。下次运行查询时,您只需将新值绑定到它并完全跳过第一步(!)
  • 可以多次调用此时的Execute (如果出现可恢复的错误),而无需重复前两个步骤

有关更多信息,请在 Google 中搜索目标数据库的“sql prepare bind execute”

于 2012-07-14T19:30:35.360 回答
1

我建议您使用自定义占位符:

char querystring[]="INSERT INTO accounts (user, protocol, handle, password, autoconnect, tag) values ({param_user_id}, {param_protocol}, {param_handle}, {param_password}, {param_autoconnect}, {param_tag});"
parameterizeQuery(querystring, "user_id", user_id);
parameterizeQuery(querystring, "protocol", acc_protocol);
//do this for all remaining fields
g_string_printf(q, querystring);

虽然parameterizeQuery可能看起来像这样:

void parameterizeQuery(char stringofquery[], char parameterstring[], char parametervalue[])
{
    //PSEUDO-CODE: stringofquery.str_replace("{param_"+parameterstring+"}", g_string_mysql_escape_param(parametervalue));
}

这会有点短,但我不熟悉 glib。

于 2012-07-14T20:16:14.520 回答