SOFTELメモ Developer's blog

会社概要 ブログ 調査依頼 社員募集 ...

【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 など)。

関連するメモ

コメント