MySQLのDROP DATABASEでWARNINGが表示されない事象

 DROP DATABASE IF EXISTS ... で存在しないデータベースをドロップしようとしたときに、WARNING が表示されない事象があったので紹介します。

IF EXISTS (テーブルの場合)

 MySQLDROP文には "IF EXISTS" というオプションがあり、たとえばテーブルの場合は、以下のように使います。

mysql> use test
mysql> DROP TABLE IF EXISTS mytable999;                                                                                             
Query OK, 0 rows affected, 1 warning (0.02 sec)

 mytable999 というテーブルは存在しませんが、IF EXISTS 句のおかげでエラーにはならず正常終了しています。
ワーニングがあるようなので見てみます。
 

mysql> SHOW WARNINGS;
+-------+------+---------------------------------+
| Level | Code | Message                         |
+-------+------+---------------------------------+
| Note  | 1051 | Unknown table 'test.mytable999' |
+-------+------+---------------------------------+

 そんなテーブルは存在しないよ、と言っています。
・・と、こんな感じの動作をします。

IF EXSISTS (データベースの場合)

 DROP DATABSE でも同じく IF EXISTS 句が使えるのでやってみます。

mysql> DROP DATABASE IF EXISTS test999;
Query OK, 0 rows affected, 1 warning (0.00 sec)

 test999というデータベースは存在しないので、ワーニングがでています。テーブルの時と同じように見てみましょう。

mysql> SHOW WARNINGS;                                                                                                            
Empty set (0.00 sec)

 なんと! ワーニングが表示されません!

WARNINGをすぐに表示するオプションなら表示される

 ということをtwitterに書いたら、すかさずとみたさんた実験してくれました。 mysqlコマンドラインクライアントは --show-warnings というオプションを付けて起動することで、warningが出た時にすぐにwarningメッセージを表示してくれる機能があります。(デフォルトではワーニングは「発生したという事実(と個数)」を表示するだけで、メッセージは表示されません)

 ワーニングが内部で発生していないというわけではないようです。ということは、内部的な後続処理でワーニングが消されてしまったという可能性が考えられます。

クエリが投げられていることを確認する

 STATUSの Questions で、これまでMySQLサーバに投げられたリクエストの数がわかるので、これを監視してみる方法があります。
まずテーブルのドロップで、動作を確認してみます。

mysql> SHOW STATUS LIKE '%Questions%';                                                                                           
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Questions     | 42    |
+---------------+-------+

 42このクエリがこれまで投げられたということです。ここでテーブルをDROP して、再びQueriesを確認してみると、

mysql> DROP TABLE IF EXISTS mytable999;
Query OK, 0 rows affected, 1 warning (0.01 sec)

mysql> SHOW STATUS LIKE '%Questions%';                                                                                           
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Questions     | 44    |
+---------------+-------+

 44になりました。 DROP TABLE で1クエリ、SHOW STATUS 自身で1クエリ投げているので、2だけ増えるのは納得の結果です。


 では DROP DATABASE ではどうなるか。

mysql> SHOW STATUS LIKE '%Questions%';                                                                                           
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Questions     | 51    |
+---------------+-------+

mysql> DROP DATABASE IF EXISTS test999;
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> SHOW STATUS LIKE '%Questions%';                                                                                           
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Questions     | 54    |
+---------------+-------+

 なんと、3増えました。仮説を裏付ける結果となりました。
そしてこの結果を、よりダイレクトにとみたさんが確認してくれました。私が今回さくっと試した環境は、事情があってパラメタをいじりたくなかったので試せなかったのですが、MySQLサーバオプションで一般ログを出力するようにすることで、どんなクエリが投げられたのかを確認することができます。

 ということで、DROP DATABASE のあとに 内部的に SELECT DATABASE() が投げられていることがわかりました。これにより発生したワーニングが消されてしまっているということですね。

さぁバグ報告だ! と思ったら・・・先人たちの報告

 調べてみると、すでにbugs.mysql.comへの報告が行われていました。2015年のことです。

MySQL Bugs: #79684: "drop database if exists" says "1 warning", but "show warnings" returns nothing

 同じ動作に気づいた人もいるようで、2017年、2018年にもそれぞれ同様の動作が報告されています(報告前に調べましょう)。

MySQL Bugs: #86989: Missing warning after DROP DATABASE IF EXISTS for a non-existent database
MySQL Bugs: #90058: Note for dropping a non-existent table not shown


 まぁ重要度が低いと考えられているのか、4年たっても直す気配がない様子ですね。 
こういうこともあるので、もしかしたら --show-warnings はデフォルトでオンにしておいてもいいのかなという気が、少ししてきました。これによってどれくらい、鬱陶しいメッセージが増えてしまうか、との兼ね合いなのでしょうけれど。


 なお、この実験をしている最中、どうも私が無意識に TABLE と DATABASE をよく打ち間違えていたようで、twitter上でも(おそらく間違えて打った結果を勘違いして)混乱する情報を出してしまって失礼しました。 「そんな結果にならないよ」と、すかさずツッコミを入れてくれたとみたさん、ありがとうございました!


おまけ

 この日記を書くために改めて実験していて、「そういやこのサーバ、Queriesがこんなに小さな値のわけがないんだけど・・・」と気づきました。
そうか、Queries は、GLOBALとSESSION で、それぞれ値を持っているのですね。 普段気にしないから認識の外にありましたが、副次的な学びでした(笑)。

mysql> SHOW GLOBAL STATUS LIKE 'Questions';                                                                                      
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Questions     | 23324 |
+---------------+-------+

mysql> SHOW STATUS LIKE 'Questions';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Questions     | 46    |
+---------------+-------+