カタログヘッダファイルの肝心な部分は、カタログにおける行の配置を記述するC構造体定義です。
これはCATALOG
マクロで始まりますが、Cコンパイラの観点からすると、単にtypedef struct
FormData_
の短縮形です。
構造体の各々のフィールドは、カタログの列を生成します。
フィールドにはcatalogname
genbki.h
に記述されたBKIプロパティマクロを使って注釈を付けることができます。
たとえば、フィールドのデフォルト値を定義したり、NULLが許されるかどうかのフラグを付けることができます。
CATALOG
行にも注釈が付けられます。
genbki.h
に記述されたBKIプロパティマクロを使って、共有リレーションであるかどうかといった、そのカタログ全体のプロパティを定義することができます。
システムカタログキャッシュのコード(そして一般的にたいていのカタログを触るコード)は、すべてのシステムカタログタプルに固定長部分が実際に存在するとみなします。
システムカタログキャッシュのコードは、C構造体定義をその固定部分にマップするからです。
したがって、すべての可変長フィールドと、NULLを許容するフィールドは、最後尾に置かれなければならず、また、構造体のフィールドとしてはアクセスできません。
たとえば、pg_type
.typrelid
をNULLにしようとすると、他のコード部分がtypetup->typrelid
を参照しようとして失敗します。(あるいはもっと悪いことにtypetup->typelem
を参照中に失敗します。なぜなら、そのフィールドはtyprelid
の後に来るからです。)
これはランダムなエラーとなるか、あるいはセグメンテーション違反にすらなってしまいます。
この種のエラーから部分的に身を守るためには、可変長あるいはNULLを許容するフィールドはCコンパイラから直接見えないようにすべきです。
これは#ifdef CATALOG_VARLEN
... #endif
の中に入れることで達成できます。(ここで、CATALOG_VARLEN
は、決して定義されないシンボルです。)
これにより、Cコードが不注意で存在しないフィールドにアクセスしようとしたり、オフセットが違うフィールドにアクセスしようとするのを防ぐことができます。
不正な行を作るのを防ぐ独立したガードとして、NULLを許容しないすべての列をpg_attribute
でそのように宣言することを要求します。
ブートストラップコードは、固定長で、かつ、NULLを許容したり可変幅である列の次ではないカタログ列に対して自動的にNOT NULL
のマークを付けます。
このルールが不適切なら、BKI_FORCE_NOT_NULL
とBKI_FORCE_NULL
を必要に応じて使ってマーキングを修正できます。
フロントエンドのコードはすべてのpg_xxx.h
カタログヘッダファイルをincludeすべきではありません。
バックエンド以外ではコンパイルできないCコードを含んでいるかもしれないからです。
(典型的には、src/backend/catalog/
ファイル中に関数宣言を含んでいることによって起こります。)
その代わりに、フロントエンドは生成されたpg_xxx_d.h
ヘッダーをincludeできます。
このファイルは、OIDの#define
と、クライアント側で必要になるデータを含んでいます。
カタログヘッダー中のマクロやその他のコードをフロントエンドから見えるようにしたい場合は、#ifdef EXPOSE_TO_CLIENT_CODE
... #endif
で該当セクションを囲むことにより、genbki.pl
がそのセクションをpg_xxx_d.h
にコピーするように指示してください。
少数のカタログは非常に基本的なものなので、ほとんどのカタログで使用されるBKI create
コマンドですら作成できません。そのコマンドが、新しいカタログの記述をこれらのカタログに書き込む必要があるからです。
これらはブートストラップカタログと呼ばれ、定義するためには大量の追加の作業が必要です。
pg_class
とpg_type
のあらかじめロード済みの内容上に手動で適切なエントリを用意し、後のカタログ構造への変更に合わせてそれらのエントリを更新する必要があります。
(また、ブートストラップカタログはpg_attribute
中のロード済みのエントリを必要としますが、幸いにも最近はgenbki.pl
が適切に処理してくれます。)
可能ならば、新しいカタログをブートストラップカタログとして作るのは避けてください。