Help us understand the problem. What is going on with this article?

RailsにてSQLでのワイルドカード文字をエスケープしてくれるsanitize_sql_likeは何をしているのか

More than 1 year has passed since last update.

はじめに

Rails4.21より、Stringクラスのオブジェクト内にある”%”や”_”といったLIKE句でのワイルドカード文字をエスケープしてくれるsanitize_sql_likeメソッドが使えるようになっています。

検索機能等においてLIKE句はよく使用するものであり、ワイルドカードはきちんとエスケープしないと非常に重いSQLが発行されることになりかねません

今回はソースコードを読むという行為の練習も兼ねて、このsanitize_sql_likeというメソッド内でどのような動作が行われているのかを追っていこうと思います

まずはソースコード

def sanitize_sql_like(string, escape_character = "\\")
  pattern = Regexp.union(escape_character, "%", "_")
  string.gsub(pattern) { |x| [escape_character, x].join }
end

このメソッドはstringとエスケープのための文字escape_character(デフォルトでは"\\")を引数にとります
実行内容としては2つのステップに分かれていて、

  1. エスケープ文字とワイルドカードとして認識される文字にマッチする正規表現を生成、patternに代入

  2. stringの中にある文字でpatternとマッチする文字をエスケープ文字と連結してエスケープ

この2つの行程を通して引数string をsanitize(消毒)していきます。

エスケープ文字とワイルドカードとして認識される文字にマッチする正規表現を生成、patternに代入

  pattern = Regexp.union(escape_character, "%", "_")

SQLのLIKE検索において"%", 及び”_”はワイルドカード文字として認識されてます。
前者は任意の数の文字、後者は唯一つの文字のワイルドカードとして機能します。
12.5.1 文字列比較関数

これらをエスケープするためにはまずこれらの文字を判別する必要があるわけです。

そのためにRegexp.unionというRegexpのクラスメソッドを使用します。
Regexp.unionは引数として与えた文字にそれぞれマッチする正規表現を”|”で連結し、引数のどれかにマッチする正規表現を返します。
singleton method Regexp.union

このコードではRagexp.union の引数として2つのワイルドカード及びエスケープのための文字\\(\単体では記述できないため)をとり、判別するための正規表現を生成し変数patternに入れています。

stringの中にある文字でpatternとマッチする文字をエスケープ文字と連結してエスケープ

  string.gsub(pattern) { |x| [escape_character, x].join }

gsubはStringクラスのインスタンスメソッドで、文字列の中で正規表現にマッチした部分を指定の文字列に置換します。
gsub, gsub! (String)
このメソッドを使いワイルドカード文字をエスケープされるように置換していきます。
ブロック内のxには先程生成した正規表現patternにマッチする文字が入っていき、このxに対してエスケープ文字として指定した\\を連結して置き換えることでエスケープが完了となります

わかりやすくするとすれば

  string.gsub(pattern) { |matching_character| [escape_character, matching_character].join }

という形になりますかね

まとめ

railsには様々な便利メソッドがありますが、当然それらも何かしらのコードで作られています。今回は正規表現の勉強も兼ねてメソッドのソースコードがどのような動作をしているかを追ってみました。
プログラミングスクールの講師の方からも公式のリファレンスやソースコードを参照する癖をつけようとよく言われていましたがソースコードにもソースコードがあるわけなのでこの追求に終わりはないとも感じます

エンジニアとして転職したい23歳男性(関東)にご興味あればぜひ連絡ください(懇願)

最後まで読んでいただきありがとうございます!

参考

Ruby 1.8.7 リファレンスマニュアル
MySQL 5.6 リファレンスマニュアル
Rubyリファレンス(お世話になっています)
sanitize_sql_like(API dock)

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away