PostgreSQL18がやってくる(2) システムカタログの差分

# はじめに
にゃーん

今回は、PostgreSQL 17とPostgreSQL 18devのシステムカタログの差分を調べてみる。
まだbetaリリース前の版なので、今後変わっていく可能性が大きいけど、現時点の版で調査をしてみた。
なお、システムビューの差分については、この記事とは別に調査結果をまとめる。

## 調査方法
PostgreSQL 17とPostgreSQL 18dev(2025-03-29 commitid d6d8054dc72d4844f52f1552f8d3074c16987e32)それぞれで以下の手順を実施。

* それぞれ、データベースクラスタを新規に作成して起動する。
  * ``-U postgres``オプションと``-c "port=xxxxx"``と``-D (ディレクトリ名)``のみ指定して作成
* psqlでpostgresデータベースにログイン
* `\o` *ファイル名* メタコマンドで出力先ファイルを指定
* `\a` メタコマンドで整形用の空白が入らないようにする。
* 以下のSELECT文を実行してpsqlを終了する。

```sql
SELECT c.relname, attname, atttypid
FROM pg_class c JOIN pg_attribute a ON (a.attrelid = c.oid) JOIN pg_namespace ns ON (c.relnamespace = ns.oid)
WHERE ns.nspname = 'pg_catalog' AND c.relkind ='r'
ORDER BY c.relname, a.attname
;
```
ソートはリレーション名と属性名にする。（あえてリレーション内の属性の並び番号ではソートしない）

* psqlを終了する。
* PostgreQSL 17の検索結果ファイルと、PostgreSQL 18devの検索結果ファイルをdiffる。

# 調査結果概要
システムテーブルのテーブル単位での新規追加はない（つまり新規のDDLコマンドの追加はない）が、いくつかの列の増減があった。

|テーブル名|変更種別|修正概要|
|:--|:-:|:--|
|pg_attribute|変更|attcacheoff列の削除|
|pg_class|変更|relallfrozen列の追加|
|pg_constraint|変更|conenforced列の追加<br>conperiod列の追加|
|pg_publication|変更|pubgencols列の型変更|

# 各テーブル毎の修正内容
## pg_attribute
* attcacheoff列が削除された。

### attcacheoff列の削除
PostgreSQL文書の説明では
> ストレージ内では常に-1だが、メモリ内の行記述子にロードされると、行内の属性オフセットをキャッシュするように更新される。

とのこと。たしかに上の説明を読む限りでは、システムカタログの列として持っておくお見はあまりなさそうには読めるが・・・。

## pg_class
* relallfrozen列が追加された。

### relallfrozen列の追加
relallfrozen列はint4型の列。
PostgreSQL文書の説明では、
> テーブルの可視性マップにおいて、すべて凍結と表示されているページの数。これは、自動バキュームを起動するための推定値。また、手動バキュームのスケジューリングやバキュームの凍結動作のチューニングのために、relallvisibleと共に使用することもできる。
VACUUM、ANALYZE、CREATE INDEXなどのいくつかのDDLコマンドによって更新される。

とのこと。ただ、現状のPostgreSQL文書をざっと眺めた感じでは、この列の追加による、各コマンドへのオプションの追加等はなさそうに見える。

## pg_constraint
* conenforced列が追加された。
* conperiod列が追加された。

### conenforced列の追加
conenforced列はbool型の列。
PostgreSQL文書の説明では、
> 制約は強制されるか？
現在、CHECK制約に対してのみfalseにできます。

と書かれている。
``ALTER TABLE``でCHECK制約を設定した列の有効/無効が設定できるようになるのかな。

ということで、PostgreSQL 17/18dev文書 ``ALTER TABLE``のSynopsisを比較すると、18devでは
```sql
[ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ] [ ENFORCED | NOT ENFORCED ]
```
のように``ENFORCED``, ``NOT ENFORCED``というオプションが追加されている（``CREATE TABLE``も同様）。
定義した制約を（例えばデータロード処理前に）``ALTER TABLE ... NOT ENFORCED ...``で無効化して、データロード後に再度有効化する、みたいな使い方ができるんだろうか。

### conperiod列の追加
conperiod列はbool型の列。
PostgreSQL文書の説明では、
> この制約は、WITHOUT OVERLAPS（主キーと一意制約の場合）またはPERIOD（外部キーの場合）で定義されます。

となっている。``CREATE TABLE``や``ALTER TABLE``で設定可能な制約の種類が増えるということかな。

ということで、PostgreSQL 17/18dev文書 ``ALTER TABLE``のSynopsisを比較すると、18devでは
```sql
  UNIQUE [ NULLS [ NOT ] DISTINCT ] ( column_name [, ... ] [, column_name WITHOUT OVERLAPS ] ) index_parameters |
  PRIMARY KEY ( column_name [, ... ] [, column_name WITHOUT OVERLAPS ] ) index_parameters |
```
```sql
  FOREIGN KEY ( column_name [, ... ] [, PERIOD column_name ] ) REFERENCES reftable [ ( refcolumn [, ... ]  [, PERIOD refcolumn ] ) ]
```
のようにオプションが増えているようだ（``CREATE TABLE``も同様）。

## pg_publication
pg_publicationではpubgencols列が追加された。

### pubgencols列の追加
pubgencols列はchar型の列。
PostgreSQL文書の説明では、
> PUBLICATION列リストがない場合に、生成列の複製を処理する方法を制御する： 
n = PUBLICATIONに関連付けられているテーブル内の生成列を複製しない。 
s = PUBLICATIONに関連付けられているテーブルに格納されている生成列を複製する。

これは18devに入る予定の（テーブルに実体を持たない）仮想生成列に関係していそう。
仮想生成列がPUBLICATION対象列として明示的に指定されていないときに、その仮想生成列の値をSUBSCRIBERに送るのかどうかを制御するのかな。

PostgreSQL 17/18dev文書の``CREATE PUBLICATION``を比較すると、18devでは``WITH ( publication_parameter [= value] [, ... ] ) ``で指定可能なパラメータ``publish_generated_columns (enum)``が増えている。

このパラメータの説明を見ると
> PUBLICATIONに関連付けられたテーブルに存在する生成列を複製するかどうかを指定する。指定可能な値はnoneとstored。
既定値は none で、PUBLICATIONに関連付けられたテーブルに存在する生成列は複製されない。
stored に設定すると、PUBLICATIONに関連付けられたテーブルに存在する生成列が複製される。


# おわりに
現時点ではシステムカタログの差分はそれほど多くないが、システムカタログの差分→DDLコマンドへの何らかの変更を伴うので、やはり調べておくに越したことはない。
とりあえず、
* ALTER TABLE
* ALTER PUBLICATION
* ANALYZE
* CREATE INDEX
* CREATE PUBLICATION
* CREATE TABLE

あたりのSQLコマンドには影響がありそうだ。