patorashのブログ

方向性はまだない

SQLiteのLIKE演算子はデフォルトでESCAPE文字が設定されていない

私はimyouというニックネーム管理用gemを公開しているのですが、開発時にPostgreSQLを使っていました。 しかし、RailsのデフォルトのデータベースはSQLiteなので、SQLiteで開発したほうがよかろうと考え、SQLiteに変更してテストを実行したところ、なんと落ちてしまいました。

落ちた原因の調査

テストで実行されているSQLが変わるのか?と思い、to_sqlを挟んで調査してみましたが、SQL文はほぼ同じ。PostgreSQLの場合はILIKEになるくらい。

落ちていたテストは、LIKE演算子にアンダーバーを含んだ文字列でした。sanitize_sql_likeメソッドを使っているから、_もしっかりエスケープされているから問題ないはず…。と思っていたのですが、どうもSQLiteでは、明示的にESCAPE文字列を指定しないといけないようでした。PostgreSQLでも明示的に指定はできますが、デフォルトは\(バックスラッシュ)です。

明示的に指定していないため、エスケープされた文字列はfoo\_barのようになっているものの、バックスラッシュと任意の一文字と合致する条件となってしまっていました。

対処

sanitize_sql_likeメソッドの第二引数はエスケープ文字の指定なので、'\\'を指定するように修正しました。 こうすることで、WHERE name LIKE '%foo\_bar%' ESCAPE '\'というSQLに変わり、SQLiteでも問題なくエスケープされるようになりました。

まとめ

SQLite_を含むパターンマッチを行う場合はエスケープ文字をちゃんと設定しましょう。

なお、imyouは、この問題を修正したバージョン 1.4.2 をリリース済みです。