GA

2023/05/08

MySQL 8.0でtx_isolationを使わせるようにするパッチ

TL;DR

  • ちょっと試してみただけなのでフツーに使うことはまずない。自分ですら使おうと思っていない。

パッチはこれだけ。

$ diff ./sql/sys_vars.cc.orig ./sql/sys_vars.cc
5196a5197,5204
> // NO_CMD_LINE - different name of the option
> static Sys_var_transaction_isolation Sys_tx_isolation(
>        "tx_isolation", "Default transaction isolation level."
>        "This variable is deprecated and will be removed in a future release.",
>        UNTRACKED_DEFAULT SESSION_VAR(transaction_isolation), NO_CMD_LINE,
>        tx_isolation_names, DEFAULT(ISO_REPEATABLE_READ), NO_MUTEX_GUARD,
>        NOT_IN_BINLOG, ON_CHECK(check_transaction_isolation));
>

両方使える ( tx_isolation がdeprecatedで transaction_isolation が推奨 ) MySQL 5.7.42の記述はこんな感じ。

https://github.com/mysql/mysql-server/blob/mysql-5.7.42/sql/sys_vars.cc#L4221-L4238

型としては Sys_var_tx_isolation で受けて、他のコードでトランザクション分離レベルを参照する時も thd->tx_isolation とか thd->variables.tx_isolation で参照している。

MySQL 8.0ではこれを逆に tx_isolationSys_var_transaction_isolation 型に受けるようにすれば良さそうな気がした。

https://github.com/mysql/mysql-server/blob/mysql-8.0.33/sql/sys_vars.cc#L5197-L5202

言うても thd->tx_isolationtx_isolation のままっぽい。

https://github.com/mysql/mysql-server/blob/mysql-8.0.33/sql/sql_class.cc#L1087

一方で、 substitute の属性はなくなっているのでdeprecated warningとかを出すのはそのままでは無理な気がするけど試してないし気にしていない。

https://github.com/mysql/mysql-server/blob/mysql-5.7.42/sql/sys_vars.h#L2100-L2116

https://github.com/mysql/mysql-server/blob/mysql-8.0.33/sql/sys_vars.h#L2343-L2354


というわけで

mysql80 9> SELECT @@version, @@tx_isolation;
+--------------+-----------------+
| @@version    | @@tx_isolation  |
+--------------+-----------------+
| 8.0.33-debug | REPEATABLE-READ |
+--------------+-----------------+
1 row in set (0.00 sec)


出来上がりはしたけど、使わずに済むことを祈る。

2023/05/04

DATETIME型と現在時刻の差分が秒数でほしい時に"-"で比較してはいけない

TL;DR

  • TIMESTAMPDIFF を使う
  • 知ってたはずなのにやらかしたので自戒を込めてメモ

mysql80 65> CREATE TABLE t11 (dt DATETIME);
Query OK, 0 rows affected (0.14 sec)

mysql80 65> INSERT INTO t11 VALUES (NOW());
Query OK, 1 row affected (0.05 sec)

mysql80 65> SELECT * FROM t11;
+---------------------+
| dt                  |
+---------------------+
| 2023-05-04 06:23:00 |
+---------------------+
1 row in set (0.01 sec)

この時刻との差が(整数の)秒が欲しいからと言って、

mysql80 65> SELECT NOW(), dt, NOW() - dt FROM t11;
+---------------------+---------------------+------------+
| NOW()               | dt                  | NOW() - dt |
+---------------------+---------------------+------------+
| 2023-05-04 06:23:10 | 2023-05-04 06:23:00 |         10 |
+---------------------+---------------------+------------+
1 row in set (0.00 sec)

こうしてはいけない。

mysql80 65> SELECT NOW(), dt, NOW() - dt FROM t11;  -- 期待したのは70
+---------------------+---------------------+------------+
| NOW()               | dt                  | NOW() - dt |
+---------------------+---------------------+------------+
| 2023-05-04 06:24:10 | 2023-05-04 06:23:00 |        110 |
+---------------------+---------------------+------------+
1 row in set (0.01 sec)

NOW() - dtCAST(NOW() AS SIGNED) - CAST(dt AS SIGNED) に変換されるので、 20230504062410 - 20230504062300 になるのでMySQL的には整数の110を返す。

基本、秒単位でしか離れないところで、分をまたいだ時だけ値がジャンプしてて変だなと思うまで思い出さなかった。反省。

正しくはTIMESTAMPDIFFでこう(名前からして、引数をUNIXTIMEにしないといけないかと思って雑にやったのが良くない…)

mysql80 65> SELECT NOW(), dt, NOW() - dt, TIMESTAMPDIFF(SECOND, dt, NOW()) FROM t11;
+---------------------+---------------------+------------+----------------------------------+
| NOW()               | dt                  | NOW() - dt | TIMESTAMPDIFF(SECOND, dt, NOW()) |
+---------------------+---------------------+------------+----------------------------------+
| 2023-05-04 06:26:51 | 2023-05-04 06:23:00 |        351 |                              231 |
+---------------------+---------------------+------------+----------------------------------+
1 row in set (0.00 sec)