【MySQL】 !!が?(エクスクラメーションマークを2個つなげると動きがおかしい)
問題
否定の否定をしたくて、エクスクラメーションマーク2つ使ったSQLを書いたら、結果がおかしかった。
mysql> select !!0; +-----+ | !!0 | +-----+ | 1 | +-----+ 1 row in set (0.00 sec)
正しい結果は0じゃないの? 私間違ってる?
答え
バグでした。
http://bugs.mysql.com/bug.php?id=55477
報告はだいぶ古く、2010/07/22。演算子のパースのバグみたいです。
何が起きるかというと、いくつか例を。
mysql> select version(), 123, !123, !!123, !(!123), not 123, not not 123;
+------------+-----+------+-------+---------+---------+-------------+
| version() | 123 | !123 | !!123 | !(!123) | not 123 | not not 123 |
+------------+-----+------+-------+---------+---------+-------------+
| 5.1.47-log | 123 | 0 | 0 | 1 | 0 | 1 |
+------------+-----+------+-------+---------+---------+-------------+
1 row in set (0.00 sec)
/* 意味がわからない */
mysql> select version(), !0, !!0, !!!0, !!!!0, !!!!!0, !!!!!!0;
+------------+----+-----+------+-------+--------+---------+
| version() | !0 | !!0 | !!!0 | !!!!0 | !!!!!0 | !!!!!!0 |
+------------+----+-----+------+-------+--------+---------+
| 5.5.15-log | 1 | 1 | 0 | 0 | 1 | 1 |
+------------+----+-----+------+-------+--------+---------+
1 row in set (0.01 sec)
/* !! が ! とみなされているかのような動き */
mysql> SELECT !>0;
+-----+
| !>0 |
+-----+
| 1 |
+-----+
1 row in set (0.00 sec)
/* なぜか動く。Syntax Error にならない。 */
mysql> SELECT !=0;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '!=0' at line 1
/* これはダメなんですね(当然だけど) */
詳細はバグ報告のページのとおり(http://bugs.mysql.com/bug.php?id=55477)。
これはSQLパーサーのバグです。
‘>’, ‘<‘, ‘!’, ‘=’ など、演算子の一部の可能性がある文字に対して、SQLパーサーは2文字目を見つけようとします。
そして、’>=’, ‘<=’, ‘!=’, …などの2文字の演算子かどうか確認します。
それが2文字の演算子なら、そのように処理をする。
それが2文字の演算子でないとき、パーサーは’!’などの最初の文字だけ返します。2文字目は捨てられます。
“select !<0" などが、文法エラーになるべきなのに、実際には、'<' が捨てられて、"select !0" として解釈されて、動いてしまいます。
否定の否定をしたいときや、booleanにしたいときに!!をしてしまう人は、MySQLでは要注意ですね。バグが直るまで括弧をつけるか、スペースを入れる必要ありです( !(!123) もしくは ! !123 など)。
コメント