MySQLの cp932環境でのUPPER()関数の不具合

 日本MySQLユーザ会(MyNA)のメーリングリスト(http://www.mysql.gr.jp/ml.html)で、日本語の文字列検索が期待した動作をしないという質問がありました。なにか惹かれるものがあったのか、私も含め、滅多にMLに技術的なことを投稿しない顔ぶれが反応していてわくわくしました(笑)。
 何人もの、数回にわたるやりとりの後に実際のSQL文を見せてもらうと、、、、 UPPER(col_name) LIKE "%ビタミン%" のような検索をしていることが発覚。 ここ!ここですよ!一番大事な情報は。 「UPPERして検索したら」なんてやりとりの中で一度も出てなかったじゃないですかぁ〜!
 ということで立岡さんが早速 MySQL開発チームのバグトラックに報告してくれました。パッチ付き。素早さに感動しました。(http://bugs.mysql.com/bug.php?id=44352)


 現象は、というと、「CP932(SJIS)環境で UPPER() または LOWER() 関数を使用すると、マルチバイト文字であることを無視してバイナリ単位(1バイト単位)で UPPER, LOWER の変換を行ってしまう(文字が変化してしまう)」というものです。

    • テーブルを作成し、データを3件INSERT。
mysql> create table t (a varchar(16)) engine=myisam default charset=cp932;
mysql> insert into t values ("ビタ");
mysql> insert into t values ("ABC");
mysql> insert into t values ("abc");
    • 問題の日本語文字でUPPER()の挙動を確認
mysql> select * from t WHERE upper(a)="ビタ";
Empty set (0.01 sec)

mysql> select * from t WHERE upper(a)="コタ";
+------+
| a    |
+------+
| ビタ | 
+------+
1 row in set (0.00 sec)
    • UPPER()関数によって CP932の2バイト目がUPPERされてしまっていることの確認(不具合と思います)
mysql> SELECT a, HEX(a), HEX(UPPER(a)) FROM t;
+------+----------+---------------+
| a    | HEX(a)   | HEX(UPPER(a)) |
+------+----------+---------------+
| ビタ | 8372835E | 8352835E      | ←"ビ" の2バイト目が UPPER()されてる!(笑)
| ABC  | 414243   | 414243        | 
| abc  | 616263   | 414243        | 
+------+----------+---------------+
3 rows in set (0.00 sec)


 MySQL 5.0, 5.1 (たぶん4.1も?)で発生します。あまり品の良い検索方法とは思えませんが、もしこのように UPPER を使用している方がいたらご注意を! 明確なパッチを立岡さんが報告提案してくださっているので、割合早く(次の次のバージョン?)のタイミングで取り入れられると思います。 お急ぎの方は自分でパッチを当てて(4行を2箇所の計8行修正するだけ)コンパイルするのも良いかもしれませんね。



 余談ですが、この(誤った挙動による)変換で私が気に入っているやつ(CP932環境で実行)。
もともと何かの呪文だったと思いますが、いっそう呪文らしくなりました。

mysql> SELECT UPPER("ビビデバビデブー");
+---------------------------+
| UPPER("ビビデバビデブー") |
+---------------------------+
| ココェグコェザー          | 
+---------------------------+