在c中构建SQL是一项痛苦的工作。构建这样的东西需要花费很多时间。我是glib的新手。它有助于字符串操作。但我没有找到任何缩短查询构建代码。在这里查看示例。
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来说尤为真实。
答案 0 :(得分:1)
我只回答你的最后一个问题(“有任何改进的想法吗?”)。
您在代码中执行的操作仅适用于某些一次性数据库访问,或者非常罕见的访问。每当新的请求文本到达DB服务器时,与任何缓存的字符串都不匹配,服务器就必须花费大量时间来准备要执行的语句。准备工作通常占查询总执行时间的50-90%。
现在,我建议你做的改进是将数据库访问分为三个阶段:准备,绑定,执行:
有关更多信息,请搜索Google为您的目标数据库“sql prepare bind execute”
答案 1 :(得分: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。
答案 2 :(得分:1)
我会推荐g_strdup_printf。
这允许您摆脱缓冲区相关的怪癖,并启用printf
类似字符串的使用。所有你需要处理的是生成缓冲区的解除分配。
为了正确转义,我建议您查看g_strcanon,它允许搜索和替换字符。