私が歌川です

@utgwkk が書いている

MySQLの生成カラムをMODIFY (CHANGE COLUMN) できるかどうかはあんまり自明じゃない

この記事のタイトルにあることの理由は MySQL :: MySQL 8.0 リファレンスマニュアル :: 13.1.9.2 ALTER TABLE および生成されるカラム を読んだら分かります。


生成カラムの式を変えてsqldefでマイグレーションを反映したら、DROP COLUMNしてADD COLUMNするDDLが実行されたことで、表題の件に気づいた。

ものすごく単純化すると、たとえば以下のようなDDLが実行されることがある。

ALTER TABLE `users` DROP COLUMN `id_mod`;
ALTER TABLE `users` ADD COLUMN `id_mod` int GENERATED ALWAYS AS (id % 5) VIRTUAL AFTER `id`;

参照しているカラムをDROPされると、稼動中のアプリケーションでエラーが発生してしまう。これは都合がよくない。以下のように生成カラムに対してもCHANGE COLUMNで安全にカラム定義を変更できるはず。

ALTER TABLE `users` CHANGE COLUMN `id_mod` `id_mod` int GENERATED ALWAYS AS (id % 5) VIRTUAL;

ということで、以下のissueを起票した。

github.com

ところで (個別のDBMSの実装にもよると思うけど) sqldefが何故このようなDDLを出力するのか。この記事を書いた時点ではちゃんと実装は追っていないけど、MySQLのドキュメントを読みにいったらだいたい分かった。

dev.mysql.com

生成カラムの定義は常にin-placeに変更 (MODIFYやCHANGE COLUMN) できるわけではなく、条件によっては一度DROP COLUMNを経由する必要がある。今回適用したいマイグレーションはこの条件に当てはまらない。DROP COLUMNしてADD COLUMNするのは (一部のケースを除いて) 常に可能である。

「CHANGE COLUMNできるスキーマ変更かどうか」がうまく (sqldefの枠組みの中で) 判定できる方法が分かったらPRを出したいですね。