「\%foo」から始まる文字列を検索するクエリをハードコーディングする

SQLエスケープと聞いてやってきましたよ。2008-07-10 - T.Teradaの日記から

例えば、「\%foo」から始まる文字列を検索する場合には、どのようなSQL文を書けばよいのでしょうか。
条件は以下の通りです。
1. DBMSソフトはMySQL
2. ESCAPE節は使わない
【中略】
「\%foo」から始まる文字列を検索するSQL文は、以下のようになります。
mysql> SELECT 123 FROM dual WHERE '\\%foo456' LIKE '\\\\\\%foo%';

MySQLの場合、文字列リテラルエスケープとLIKE述語のワイルドカード(「%」、「_」)に対するエスケープの両方に「\」を使うので、こういうややこしいことになりますね。T.Teradaさんが書かれているように、以下のように考えるのがよいと思います。

LIKEに与える文字列のエスケープ処理は、以下のように行なえばよいと思います。

1. LIKE演算子ワイルドカード文字のエスケープ
「%」「_」「\」を「\」でエスケープします(当然、ワイルドカードどして機能させたい「%」「_」はエスケープしない)。
2. SQL文字列のエスケープ
「\」「'」「"」とNULLや改行文字などを「\」でエスケープします。

この2つの処理を、1、2の順番でやります(DBMS側でのSQL文の解析時には、2→1という順でデコード処理されるはずです)。

さて、ここまではコピペなのですが、本題はここからです。あまりありそうな想定ではありませんが、「\%foo」から始まる文字列を検索するクエリを(PerlJavaで)ハードコーディングするにはどうするかです。
例えば、Perlで記述した例を以下に示します。

my $sql = "SELECT * FROM dual2 WHERE a LIKE '\\\\\\\\\\\\%foo%'";

T.Teradaさんの例とは少し違いますが、これは自宅の環境で動かしてみたからです(MySQL 5.0.22 on CentOS 5.1)。「\」の数は12個です。ややこしいですね。

これは、以下のように順序だてて考えるとよいと思います。

1.ワイルドカードエスケープ 「\」→「\\」 「%」→「\%」
\%foo → \\\%foo

2.SQLの文字列リテラルエスケープ 「\」→「\\」
\\\%foo → \\\\\\%foo

3.Perlの文字列リテラルエスケープ 「\」→「\\」 「"」→「\"」
\\\\\\%foo → \\\\\\\\\\\\%foo

まぁ、このようなクエリをハードコーディングするシナリオは想定しにくいですが、もし書くとしたらこうなります。