【PostgreSQL】pg_restoreで`unsupported version`と表示されたら、pg_dumpのバージョン差異を疑う

## 概要
他所からもらったdumpファイルが、どのPostgreSQLバージョン（正確には、pg_dumpバージョン）で採られたものか分からないことって、あるでしょう？（あるんだよ）

手元のdumpファイルがリストアできないときに、「これ、聞いてたのより新しいバージョンのPg_dumpでバックアップしたやつですよね！？」って言うための根拠づくりをやっていくナレッジ。バージョン不一致時の対処方法も、軽めに選択肢だけ整理します。

| 項目 | 内容 |
|------|------|
| **取り扱う内容** | • dumpファイルのバージョン情報の確認方法<br>• バージョンの互換性に関する制約<br>• バージョン不一致時の対処方法 |
| **想定読者** | • PostgreSQLのバックアップ・リストア作業を行う人<br>• 外部から受領したdumpファイルを取り扱う人<br>• リストアを試みたが`unsupported version`と表示されて困ってる人 |
| **ゴール** | • dumpファイルのバージョン情報を容易に確認できるようになる<br>• dumpファイルバージョンの互換性問題を理解する |

## 前提知識：dumpファイルのバックアップとリストアにおける基本ルール
* 新しいバージョンの`pg_dump`で作成したダンプファイルは、古いバージョンの`pg_restore`では読み込めない
* 古いバージョンの`pg_dump`で作成したダンプファイルは、新しいバージョンの`pg_restore`で読み込むことができる
  * ただしv9.2より古いpg_dumpを使った場合は、保証対象外

これは、[PostgreSQL v15 公式](https://www.postgresql.jp/document/15/html/app-pgdump.html)にも記載されています。
> pg_dumpの出力はpg_dumpのバージョンより新しいバージョンのPostgreSQLデータベースへロード可能と想定できるようになっています。 また、pg_dumpは自身より古いバージョンのPostgreSQLデータベースを読み取ることもできます。 （現在はバージョン9.2までのサーバをサポートします。） しかし、pg_dumpはそれ自身のメジャーバージョンより新しいPostgreSQLサーバのダンプを取ることはできません。 

また、上記のルールはカスタム形式で取得したdumpファイルに適用され、プレーンテキスト形式のdumpファイルには適用されません。

## dumpファイルのメタ情報を参照する
手元のdumpファイルに対して、以下のコマンドでメタ情報を参照できます。dump取得先となったPostgreSQLバージョンとともに、dumpを生成したクライアントのpg_dumpバージョンも表示されます。
```bash
# dumpファイルの持っている情報を一部だけ参照
pg_restore -l backup.dump | head -n 12
```
結果：
```text
; Archive created at 2024-10-30 19:19:43 UTC
;     dbname: testdb
;     TOC Entries: 4
;     Compression: -1
;     Dump Version: 1.14-0
;     Format: CUSTOM
;     Integer: 4 bytes
;     Offset: 8 bytes
;     Dumped from database version: 15.8 (Debian 15.8-1.pgdg120+1)
;     Dumped by pg_dump version: 15.8 (Debian 15.8-1.pgdg120+1)
```
上記から読み取れる情報：
* **データベースバージョン**: `Dumped from database version` の行で、dump取得元のPostgreSQLバージョンが分かる
* **pg_dumpバージョン**: `Dumped by pg_dump version` の行で、dumpを生成したクライアントのpg_dumpバージョンが分かる
* **バージョンの不一致**: PostgreSQL v15に付属のpg_dumpでPostgreSQL v12のdumpをとった場合など、データベースバージョンとpg_dumpバージョンが異なることがある。これは正常な動作
* **その他の情報**: 作成日時、データベース名、ダンプフォーマット（この例では CUSTOM）なども確認できる

## リストア環境の`pg_restore`より新しい`pg_dump`で作成されたファイルはリストアできない
dumpファイルが`pg_restore`を実行しているクライアントよりも新しいpg_dumpバージョンで作られた物である場合、メタ情報の参照ができません。このとき、以下のようなメッセージが出ます。
```bash
# v15 pg_dumpで作成したファイルを、PostgreSQL v10のpg_restoreで`pg_restore -l`したときのリアクション
pg_restore: [archiver] unsupported version (1.14) in file header
```
このエラーメッセージは、dumpファイルのバージョンがリストア環境の`pg_restore`バージョンと互換性がないことを示しています。

### `pg_dump`と`pg_restore`のバージョンを確認する
前項のメッセージから、dumpをくれた相手がリストア環境より新しいバージョンのdb_dumpを使っていることが分かりました。確証を得るために、自分の環境と相手の環境とで、以下のコマンドを実行して、`pg_dump`のバージョンに差分があることを確認できます。
```bash
# pg_restoreはpg_dumpと同じバージョンになるはずだが、念のため。
# 以下、PostgreSQL v10で実行したリアクション
pg_dump --version & pg_restore --version
# pg_dump (PostgreSQL) 10.21 (Debian 10.21-1.pgdg90+1)
# pg_restore (PostgreSQL) 10.21 (Debian 10.21-1.pgdg90+1)
```

### バージョンの不一致を解決する
#### クライアントツール（pg_dump/pg_restore）のバージョンを合わせる
バージョンの不一致が確認された場合、正常にリストアするために`pg_dump`と`pg_restore`のバージョンを合わせる必要があります。データベース本体のバージョンを変更する必要はありません。クライアントツール（`pg_dump`や`pg_restore`）のバージョンを合わせればOKです。

以下の2つの選択肢から、リーダーやお客さんと相談して対応します。特に本番環境が絡む場合、承認なしに新しいツールを導入できないことがあるので、ちゃんと相談してください。

| 対応方針 | 対応内容 |
|---------|----------|
| dumpファイル作成環境で対応 | • 古いバージョンのpg_dumpを導入<br>• dumpファイルを作り直す |
| リストア環境で対応 | • 新しいバージョンのpg_restoreを導入<br>• 既存のdumpファイルをそのまま使用 |

#### クライアントツールの入手方法

##### PostgreSQLの完全インストール
開発環境など、自由にツールをインストールできる場合に採用してよさそう。該当バージョンのPostgreSQLをインストールすることで、必要なクライアントツールも一緒に入手できます。

##### バイナリのダウンロード
[PostgreSQL公式のzipアーカイブ配布サイト](https://www.enterprisedb.com/download-postgresql-binaries)から、zip形式のアーカイブをダウンロードします。アーカイブから`pg_dump`および`pg_restore`の実行ファイルを取り出して使用します。

付属のライブラリファイルも一緒に取り出さないといけないかも。まだ試したことがないので、動かされたらまた教えてください（すみません！）

##### 既存のクライアントの利用
必要なバージョンのクライアントが、既にPCへインストールされている可能性があります。以下の点を確認します。
* コマンドラインで実行している場合、正しいバージョンのPostgreSQLクライアントがあるディレクトリにパスが通っているか確認する
* pgAdminやDBeaverなどの外部ツールを使用している場合、設定で使用するクライアントのバージョンを指定できる（はず）