sue445/plant_erd の MySQL コマンドの出力を修正する PR を出した

RDB の ER 図を PlantUMLDSL で出力する plant_erd の出力を修正する PR を出した & マージされた。

plant_erdMySQL, PostgreSQL, SQLite3, OracleDB を対象に実際のデータベースにクエリを投げてテーブル定義を収集し、ER 図(に変換可能な PlantUML 向けテキスト)を出力する。

MySQL モードの時だけ出力に View が含まれていた。他のデータベースでは明確に View を取り除くためのクエリを使っていたのでバグだと判断。念の為 Issue を上げて作者に確認した後、PR を出した。

View の除外

job, person というテーブル2つと、それらから作った personal_job という View が1つあるデータベースを考える。

CREATE TABLE job (
  id int NOT NULL,
  name varchar(256),
  PRIMARY KEY (id)
);

CREATE TABLE person (
  id int NOT NULL,
  name varchar(256),
  job_id int NOT NULL,
  INDEX job_idx (job_id),
  FOREIGN KEY (job_id) REFERENCES job(id) ON DELETE CASCADE
);

CREATE VIEW personal_job AS SELECT person.name AS person_name, job.name AS job_name FROM person INNER JOIN job ON person.job_id = job.id;

修正前の時点では以下のクエリで、対象データベースのテーブル名一覧を取得していた。

SELECT table_name FROM information_schema.tables WHERE table_schema=database() ORDER BY table_name;

information_schema.tables には View も含まれているので、出力には personal_job も含んでしまう。

mysql> SELECT table_name FROM information_schema.tables WHERE table_schema=database() ORDER BY table_name;
+--------------+
| table_name   |
+--------------+
| job          |
| person       |
| personal_job |
+--------------+

テーブルと View を区別するために、where 句に table_type カラムの値を確認するようにした(table_type カラムの値は 'BASE TABLE''VIEW' のどちらか)。

SELECT table_name FROM information_schema.tables WHERE table_schema=database() AND table_type = 'BASE TABLE' ORDER BY table_name;

これによりテーブルのみを抽出することができた。

mysql> SELECT table_name FROM information_schema.tables WHERE table_schema=database() AND table_type = 'BASE TABLE' ORDER BY table_name;
+------------+
| table_name |
+------------+
| job        |
| person     |
+------------+

そもそもの経緯

当初は出力に View を含むのが仕様だと思いこんでいたので、View を除外する/View だけを出力するオプションを追加する PR を出そうかと思っていた。ユースケースをどうやって説明しようか悩んでいたが、よくよく調べたら仕様ではなくバグだったので、気兼ねなく PR を出せた。

機能追加にしろバグ修正にしろ、対象の箇所ピンポイントだけでなく周辺の実装(今回の場合は MySQL 以外の DB 向けの実装)も一緒に調べるの大事。