こんにちは、三苫です。
時々、複雑なシステムをリリースするとき新旧両方のシステムを同時に稼働し続けないといけないという状況に陥ること、ありますよね。
さらに、そのシステムは設定マスタみたいなテーブルがあって、システムはその設定値を読んで稼働するという事も、ありますよね。
さらにさらに、新しいシステムと古いシステムで、同じ設定マスタの同じレコードを読まなければいけないんだけど新しいシステムと古いシステムで別の値じゃないと動かない・・・なんてこともありますよね。
さらにさらにさらに、そういう場合たいていは新しいシステムのほうはプログラムを改修してその問題を回避できるようにするのが筋なんだけど、該当箇所の修正をするとシステムの再テスト工数が膨大になり現実的ではないというケースも泣きたいほど多いですよね。
※実際にはそんなに多くないと思います。
要件
- 新システムと旧システムで同じクエリを発行し、同じレコードを見なければならない。
- ただし、旧システムでは「X」という値を受け取り、新システムでは「Y」という値を受け取れなければならない。
- 接続ユーザ名は変えることはできない。
- 新システムと旧システムでサーバーのIPは異なる。
- システムの RDBMS は PostgreSQL とする。
つまり、簡単に言うとこういう事。
できるかな~。
実現方法
まずもともとの設定テーブルの初期状態を以下とします。
1 2 3 4 5 6 |
-- オリジナルの設定テーブル CREATE TABLE 設定値マスタ ( 設定名 TEXT PRIMARY KEY, 設定値 TEXT NOT NULL ); INSERT INTO 設定値マスタ (設定名, 設定値) VALUES ('所在地', '大阪府'); |
物理テーブルのままでは要件を満たすことはできませんので、VIEWにしないといけないことはすぐに思いつきます。けれど、VIEWにしたところで接続元を条件に加えることができないと結果を出しわけることができません。
しかしPostgreSQLは話の分かるやつです。 inet_client_addr() を使うことでリモート接続のアドレスを取得することができるのでこれを条件に使えそうです。
https://www.postgresql.jp/document/9.4/html/functions-info.html
大体こんな風にしたらいけるんじゃないかな?UNION ALL のところがポイントですね。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
-- 旧システムから参照したい値の入っているテーブル CREATE TABLE 設定値マスタ_OLD ( 設定名 TEXT PRIMARY KEY, 設定値 TEXT NOT NULL ); INSERT INTO 設定値マスタ_OLD (設定名, 設定値) VALUES ('所在地', '大阪府'); -- 新システムから参照したい値の入っているテーブル CREATE TABLE 設定値マスタ_NEW ( 設定名 TEXT PRIMARY KEY, 設定値 TEXT NOT NULL ); INSERT INTO 設定値マスタ_NEW (設定名, 設定値) VALUES ('所在地', '大阪都'); -- 上記2テーブルを inet_client_addr() の値によって切り替える不思議なビュー CREATE OR REPLACE VIEW 設定値マスタ AS SELECT 設定名, 設定値 FROM ( -- inet_client_addr() によって参照するテーブルを切り替える SELECT 設定名, 設定値 FROM 設定値マスタ_OLD WHERE inet_client_addr() = '192.168.0.1' UNION ALL SELECT 設定名, 設定値 FROM 設定値マスタ_NEW WHERE inet_client_addr() = '192.168.10.1' ) FUSHIGI; |
これで接続元によって結果が変わるという何とも不思議なビューが完成しました。
テストしてみましょう。
1 2 3 4 5 6 7 8 9 10 11 |
-- 192.168.0.1 から接続して実行 postgres=# select * from 設定値マスタ; 設定名 | 設定値 --------+-------- 所在地 | 大阪府 -- 192.168.10.1 から接続して実行 postgres=# select * from 設定値マスタ; 設定名 | 設定値 --------+-------- 所在地 | 大阪都 |
すごい!接続元のサーバーによって結果が変わってますね!
これでプログラムを改修せずにリリースできる!
実現はできたけど
と、ここまで実現方法を考えたのはいいのですが「お、おかしい!このテーブル接続するサーバーによってSELECT結果が変わる!?タスケテ!!」みたいなはまり方をする同僚の姿しか思い浮かばなかったこともあり、この方式を採用するのは(私の社内の評判的に)リスクが大きかったため断念しました。
みんなが思いつかなかったトリッキーな技で物事を解決するのはいつだって楽しいことです。ただし、その驚きがチームの混乱、怒りに変わらないかどうかを見極めることも大切です。
私は「PostgreSQL、やっぱりスゲーぜ」というはてブが一つでもつけば、それだけで満足です。むしろそれだけが今回の記事の勝利条件です。
※MySQLでも user() が user@hostname を返すので同じことを実現できると思います。
以上、新旧システム混在方法検討会の現場からお送りしました。