小ネタ:PostgreSQLのバージョンチェック
とある事情でPostgreSQLのバージョンチェックについてちょこっと調べてみた。
バージョンチェックとは
PostgreSQLはメジャーバージョン間ではデータベースクラスタの互換性がない。
なので、PostgreSQLサーバの起動プロセス(postgres, 旧postmaster)のバージョンと、データベースクラスタのバージョンが一致するかを起動時にチェックして、バージョンが異なる場合にはバージョン不一致としてエラーとし、PostgreSQLを起動しないようにしている。
このバージョンチェックのために、データベースクラスタ内にある、PG_VERSIONファイルというものを参照している。
PG_VERSIONの内容は単純にメジャーバージョン番号のみが入ったテキストファイルだ。
[nuko]$ cat $PGDATA/PG_VERSION 9.3 [nuko]$
実行例
PostgreSQLサーバのバージョンとして9.3.2を使った例を示す。
まず、PG_VERSIONのファイル自体が存在しない場合。
[nuko]$ FATAL: "/home/harada/pgdata/9.3" is not a valid data directory DETAIL: File "/home/harada/pgdata/9.3/PG_VERSION" is missing.
次にPG_VERSION内のフォーマットが不正な例
[nuko]$ cat $PGDATA/PG_VERSION 9.X [nuko]$ pg_ctl start server starting [nuko]$ FATAL: "/home/harada/pgdata/9.3" is not a valid data directory DETAIL: File "/home/harada/pgdata/9.3/PG_VERSION" does not contain valid data. HINT: You might need to initdb.
PG_VERSIONの記述形式は正しいけど、メジャーバージョンが合っていないという例。
[nuko]$ cat $PGDATA/PG_VERSION 9.2 [nuko]$ pg_ctl start server starting [nuko]$ FATAL: database files are incompatible with server DETAIL: The data directory was initialized by PostgreSQL version 9.2, which is not compatible with this version 9.3.2.
なお、バージョン番号のチェック"x.x"までしか見てないので、例えばマイナーバージョンに相当する番号をテキトーな文字にしてもスルーしてフツーに起動する。
[nuko]$ cat $PGDATA/PG_VERSION 9.3.X [nuko]$ pg_ctl start server starting [nuko]$ LOG: database system was shut down at 2014-02-15 23:43:29 PST LOG: database system is ready to accept connections LOG: autovacuum launcher started
実装
この処理は、 ./backend/utils/init/miscinit.c の void ValidatePgVersion(const char *path) という関数で実装している。
で、この関数は
PostmasterMain()→checkDataDir()→ValidatePgVersion()
という順に呼び出されている。
この関数内でまずPG_VERSIONファイルのオープンを試み、その後で
ret = fscanf(file, "%ld.%ld", &file_major, &file_minor);
fscanfでファイル内に書かれている文字列からメジャーバージョン番号とマイナーバージョン番号を取得する。
fscanf()の戻り値が2でなければ、フォーマットエラーとみなす。
その後、PG_VERSIONファイルから取得したメジャーバージョンとマイナーバージョンを定数値 PG_VERSION (このバージョンの場合は"90302")から抜き出したメジャーバージョンと比較している。
なので、PG_VERSIONファイルに"9.3.X"と書いてあっても、2つ目以降のピリオドは無視されるのだろう。
なお、定数値 PG_VERSIONはこのファイルで定義されている。
./include/pg_config.h:699:#define PG_VERSION "9.3.2"
で、ここの値はPostgreSQLをビルドインストールするときの .configure で生成しているんじゃないかと思う。きちんと確認してないけど。