DataTable#Select でのエスケープ処理
DataTable クラスは Select メソッドを使うことで条件に一致する行だけを取得することができます。
DataSet dataset = new DataSet(); DataTable table = dataset.Tables.Add("TEST_TABLE"); table.Columns.Add("COL1"); table.Columns.Add("COL2"); table.Rows.Add(new object[] { "00001", 1 }); // 行A table.Rows.Add(new object[] { "00002", 2 }); // 行B DataRow[] rows = table.Select("COL1 = '00001'"); // 行Aだけ取得できる
が、Prepared Statement とかそんな気の利いたものは無いみたいなので、入力文字をエスケープ処理しておかないと意図しない動作をすることがあります。
エスケープ処理を行う関数を捜したのですが見つからなかったので自分で書くことにしました。
通常のエスケープ
static public string Esc(string str) { return str.Replace("'", "''"); }
ただ、これで常にOKというわけではなくて、
string num = inputed; DataRow[] rows = table.Select("COL2 = " + Esc(num));
のように数値型のカラムへの条件の場合、例えば inputed が "1 or 1=1"
だとすると
DataRow[] rows = table.Select("COL2 = 1 or 1=1");
と同じ事になり、意図した動作でなくなります。この場合は
int num = int.Parse(inputed); DataRow[] rows = table.Select("COL2 = " + Esc(num.ToString()));
または
string num = inputed; DataRow[] rows = table.Select("COL2 = Convert('" + Esc(num) + "', 'System.Int32')");
のようにして型を合わせるようにします。こうしておけば想定していない入力の場合はちゃんとエラーになります。
like 検索時のエスケープ
like を使って部分一致検索をする場合は、ワイルドカードに当たる文字もエスケープします。
* と % はどちらも LIKE 比較の中でワイルドカード文字として使用できます。LIKE 句の中の文字列に * または % を使用する場合は、それらの文字を角かっこ ([]) で囲んでエスケープする必要があります。句の角かっこが含まれている場合は、角かっこ文字を角かっこで囲んで ([[]、[]] のように) エスケープする必要があります。
DataColumn.Expression プロパティ
これを実装すると以下のようになります。
static public string EscForLike(string str) { return Regex.Replace(Esc(str),@"([\[\]*%])","[$1]"); // Esc は上のヤツ }
like かそうでないかで処理が違うのはややこしいですね。