1. ホーム
  2. android

[解決済み] IN句とプレースホルダー

2022-12-02 16:59:41

質問

Androidで以下のようなSQLクエリを実行しようとしています。

    String names = "'name1', 'name2";   // in the code this is dynamically generated

    String query = "SELECT * FROM table WHERE name IN (?)";
    Cursor cursor = mDb.rawQuery(query, new String[]{names});

しかし、Androidはクエスチョンマークを正しい値に置き換えてはくれません。 以下のようにすることもできますが、これではSQLインジェクションを防ぐことはできません。

    String query = "SELECT * FROM table WHERE name IN (" + names + ")";
    Cursor cursor = mDb.rawQuery(query, null);

この問題を回避し、IN句を使用できるようにするにはどうしたらよいでしょうか。

どのように解決するのですか?

のような形式の文字列 "?, ?, ..., ?" は動的に作成された文字列で、元のSQLクエリに安全に入れることができ(外部データを含まない制限されたフォームであるため)、その後プレースホルダーを通常通り使用することができます。

関数を考えてみましょう。 String makePlaceholders(int len) を返す len のようにカンマで区切られたクエスチョンマークを返します。

String[] names = { "name1", "name2" }; // do whatever is needed first
String query = "SELECT * FROM table"
    + " WHERE name IN (" + makePlaceholders(names.length) + ")";
Cursor cursor = mDb.rawQuery(query, names);

ちょうど場所と同じ数の値を渡すことを確認してください。デフォルトの最大値は ホストパラメータの上限 は999です - 少なくとも通常のビルドでは。)


ここに一つの実装があります。

String makePlaceholders(int len) {
    if (len < 1) {
        // It will lead to an invalid query anyway ..
        throw new RuntimeException("No placeholders");
    } else {
        StringBuilder sb = new StringBuilder(len * 2 - 1);
        sb.append("?");
        for (int i = 1; i < len; i++) {
            sb.append(",?");
        }
        return sb.toString();
    }
}