MySQLで未定義のユーザ変数の表示がおかしい(8.0.20)

MySQL では @ で始まるユーザ定義変数を使うことができます。

mysql> SET @v1=123, @s1="ABC";
Query OK, 0 rows affected (0.00 sec)

 こんなふうに定義すると、SELECTなどで使うことができます。
ここで、上で定義した2つの変数と、未定義の変数をSELECT文で見てみると:

mysql> SELECT @v1, @s1, @t1;
+------+------+------------+
| @v1  | @s1  | @t1        |
+------+------+------------+
|  123 | ABC  | 0x         |
+------+------+------------+

 上で値をセットした v1, s1 は、それぞれセットしたとおりの値が表示されていますが、未定義の @t1 には "0x" と表示されてしまいました。


 値が NULL だとそうなるのか?

mysql> SET @s1=NULL;

mysql> SELECT @v1, @s1, @t1;                                                                                                     
+------+------+------------+
| @v1  | @s1  | @t1        |
+------+------+------------+
|  123 | NULL | 0x         |
+------+------+------------+

 そうではないようです。
ブランクなら?

mysql> SET @v1="";
mysql> SELECT @v1, @s1, @t1;
+------+------+------------+
| @v1  | @s1  | @t1        |
+------+------+------------+
|      | NULL | 0x         |
+------+------+------------+

 セットしたとおりにブランクが出力されます。
じゃぁ未定義の値に書き換えてしまえば再現するのでは?と試してみると

mysql> set @v1=@xxx;

mysql> SELECT @v1, @s1, @t1;
+------+------+------------+
| @v1  | @s1  | @t1        |
+------+------+------------+
| NULL | NULL | 0x         |
+------+------+------------+

 NULL になってしまう。
ちなみに、未定義の変数に未定義の値を代入すると、NULLにはならず、未定義的な値が出力されます。

mysql> SET @u1=@u2;                                                                                                              

mysql> SELECT @u1, @u2;
+------------+------------+
| @u1        | @u2        |
+------------+------------+
| 0x         | 0x         |
+------------+------------+


 最初の値に戻って、HEXを取ってみると、未定義のところは、やっぱり未定義である模様(=何か不可視な値が入っているわけではない)。

mysql>  SET @v1=123, @s1="ABC";  
mysql> SELECT HEX(@v1), HEX(@s1), HEX(@t1);
+----------+----------+----------+
| HEX(@v1) | HEX(@s1) | HEX(@t1) |
+----------+----------+----------+
| 7B       | 414243   | NULL     |
+----------+----------+----------+


ちなみにこの事象、
MySQL 8.0.20:

mysql> SELECT @v1, @s1, @t1;
+------+------+------------+
| @v1  | @s1  | @t1        |
+------+------+------------+
|  123 | ABC  | 0x         |
+------+------+------------+


MySQL 8.0.19:

mysql> SELECT @v1, @s1, @t1;
+------+------+------------+
| @v1  | @s1  | @t1        |
+------+------+------------+
|  123 | ABC  | 0x         |
+------+------+------------+

MySQL 8.0.17:

mysql> SELECT @v1, @s1, @t1;
+------+------+------------+
| @v1  | @s1  | @t1        |
+------+------+------------+
|  123 | ABC  | NULL         |
+------+------+------------+

8.0.18 は、ちょうど手元に使える環境がなかったので未確認。
8.0.18または19になったときに挙動が変わったようですね。


と、ここで今回も救世主登場。 いつもいつも、皆さんありがとうございます。

ということで、「発生しなかった」MySQL 8.0.17 の mysqlクライアント起動オプションを変更して、リトライ!

MySQL 8.0.17:

$ mysql -uroot -p --binary-as-hex
 : (略)
mysql> select @n1;
+------------+
| @n1        |
+------------+
| 0x         |
+------------+

 なったぁ!!!!


結論:
mysqlクライアントで、binary_as_hex の時には、未定義のユーザ変数は "0x" と出力される』

  ・・・・という仕様、、、、、と言っていいのかな。言いたくないな(笑)。
少なくとも 8.0.19以降変わったのは mysqlクライアントの binary_as_hex のデフォルト値だけであり、挙動そのものは、もともとそういうものだったのかもしれません。
(そして NULL に対しては表示処理で NULLを返すけど、未定義に対してはHEX化をトライしてしまうという、、やっぱり単に if 文の条件抜けのような気がしないでもない(昔から))


MySQL 8.0.19 リリースノートより:

When the mysql client operates in interactive mode, the --binary-as-hex option now is enabled by default. In addition, output from the status (or \s) command includes this line when the option is enabled implicitly or explicitly:

Binary data as: Hexadecimal

To disable hexadecimal notation, use --skip-binary-as-hex (Bug #24432545)

 たしかに、STATUS出力に新しい項目が1行加わっている!

mysql> status

                          • -

mysql Ver 8.0.20 for Linux on x86_64 (MySQL Community Server - GPL)

Connection id: 11
Current database:
Current user: root@localhost
SSL: Not in use
Current pager: stdout
Using outfile: ''
Using delimiter: ;
Server version: 8.0.20 MySQL Community Server - GPL
Protocol version: 10
Connection: Localhost via UNIX socket
Server characterset: utf8mb4
Db characterset: utf8mb4
Client characterset: utf8mb4
Conn. characterset: utf8mb4
UNIX socket: /var/run/mysqld/mysqld.sock
Binary data as: Hexadecimal
Uptime: 3 hours 49 min 39 sec

Threads: 3 Questions: 61 Slow queries: 0 Opens: 558 Flush tables: 4 Open tables: 36 Queries per second avg: 0.004