背景
Railsアップグレード作業中に db:migrate を実行したら、schema.rb の差分にこんな変更が出てきた
# before
enable_extension "plpgsql"
# after
enable_extension "pg_catalog.plpgsql"
「pg_catalog って何?壊れた?」と思ったので調べた
結論
機能的な変更はゼロ。そのままコミットして問題ない
Rails 7.2 以降、schema.rb のダンプ時に拡張のスキーマ名を含めた完全修飾名(スキーマ名.拡張名)で出力するようになっただけ
そもそも plpgsql とは
plpgsql(PL/pgSQL) は、SQLに手続き的な制御構文(if / loop / 変数)を追加する言語拡張。PostgreSQLがトリガーやストアドファンクション等の内部機能を動かすためにデフォルトで有効にしている
ポイントは、Railsが plpgsql を有効化しているわけではないということ。PostgreSQLがDB作成時にデフォルトで有効にしている plpgsql の状態を、schema.rb に記録しているだけ
pg_catalog とは
pg_catalog は、PostgreSQLのシステム情報が格納されている特別なスキーマ(名前空間)
Railsで例えると:
| PostgreSQL | Railsでのイメージ |
|---|---|
public スキーマ |
app/ 配下(自分のコード) |
pg_catalog スキーマ |
Rails gem の内部コード |
つまり pg_catalog.plpgsql は「pg_catalog スキーマにインストールされている plpgsql 拡張」を完全修飾名で表現したもの
なぜ完全修飾名に変わったのか
この変更の本来の目的は、Heroku等で拡張が heroku_ext スキーマにインストールされるケースへの対応。
# Herokuだとこういう差分が出る
enable_extension "heroku_ext.pgcrypto"
Herokuでは拡張が public ではなく heroku_ext という独自スキーマにインストールされる。スキーマ名を含めずにダンプすると、環境ごとの差異を正しく表現できない
Rails の該当CHANGELOGにはこう書かれている:
Include schema name in
enable_extensionstatements indb/schema.rb
pg_catalog.plpgsql への変更はこの対応の副産物で、plpgsql がたまたま pg_catalog スキーマに入っているからそう出力されるようになっただけ
PostgreSQL Extension について補足
PostgreSQL Extension はPostgreSQLに機能を追加するプラグインの仕組みで、Rubyでいう Gem のようなもの
-- 拡張の一覧を確認するSQL
SELECT extname, nspname
FROM pg_extension
JOIN pg_namespace ON pg_namespace.oid = extnamespace;
-- 結果例
-- extname | nspname
-- ---------+------------
-- plpgsql | pg_catalog
このクエリを実行すると、plpgsql が pg_catalog スキーマに所属していることが確認できる
感想
- Heroku対応が本来の目的で、plpgsql の表記変更はその副産物というのが面白い
- こういう「機能は変わってないけど出力が変わる」系の差分は、理由がわからないと不安
参考URL