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

私はあなたが持っている最後の質問(「それを改善するためのアイデアはありますか?」)だけに答えます。

コードで行っていることは、1回限りのDBアクセス、または非常にまれなアクセスに対してのみ十分です。キャッシュされた文字列と一致しない新しい要求テキストがDBサーバーに到着するたびに、サーバーはステートメントの実行準備に多くの時間を費やす必要があります。多くの場合、準備にはクエリの合計実行時間の50〜90%がかかります。

ここで、改善のために行うことをお勧めするのは、DBアクセスを準備、バインド、実行の3つのフェーズに分割することです。

  • 準備は、実際の値がバインドされるプレースホルダーを含む定数テキスト文字列をDBサーバーに送信する場所です。
  • バインドは、これらのプレースホルダーに値を割り当て、パラメーターをバインドする場所です。次回クエリを実行するときは、新しい値をクエリにバインドし、最初のステップを完全にスキップするだけです(!)
  • この時点での実行は、前の2つの手順を繰り返さずに、(回復可能なエラーの場合に)複数回呼び出すことができます。

詳細については、GoogleでターゲットDBの「sqlpreparebindeexecute」を検索してください

于 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 に答える