The key part of a catalog header file is a C structure definition
describing the layout of each row of the catalog. This begins with
a <literal>CATALOG</literal> macro, which so far as the C compiler is
concerned is just shorthand for <literal>typedef struct
FormData_<replaceable>catalogname</replaceable></literal>.
Each field in the struct gives rise to a catalog column.
Fields can be annotated using the BKI property macros described
in <filename>genbki.h</filename>, for example to define a default value
for a field or mark it as nullable or not nullable.
The <literal>CATALOG</literal> line can also be annotated, with some
other BKI property macros described in <filename>genbki.h</filename>, to
define other properties of the catalog as a whole, such as whether
it is a shared relation.
カタログヘッダファイルの肝心な部分は、カタログにおける行の配置を記述するC構造体定義です。
これはCATALOG
マクロで始まりますが、Cコンパイラの観点からすると、単にtypedef struct
FormData_
の短縮形です。
構造体の各々のフィールドは、カタログの列を生成します。
フィールドにはcatalogname
genbki.h
に記述されたBKIプロパティマクロを使って注釈を付けることができます。
たとえば、フィールドのデフォルト値を定義したり、NULLが許されるかどうかのフラグを付けることができます。
CATALOG
行にも注釈が付けられます。
genbki.h
に記述されたBKIプロパティマクロを使って、共有リレーションであるかどうかといった、そのカタログ全体のプロパティを定義することができます。
The system catalog cache code (and most catalog-munging code in general)
assumes that the fixed-length portions of all system catalog tuples are
in fact present, because it maps this C struct declaration onto them.
Thus, all variable-length fields and nullable fields must be placed at
the end, and they cannot be accessed as struct fields.
For example, if you tried to
set <structname>pg_type</structname>.<structfield>typrelid</structfield>
to be NULL, it would fail when some piece of code tried to reference
<literal>typetup->typrelid</literal> (or worse,
<literal>typetup->typelem</literal>, because that follows
<structfield>typrelid</structfield>). This would result in
random errors or even segmentation violations.
システムカタログキャッシュのコード(そして一般的にたいていのカタログを触るコード)は、すべてのシステムカタログタプルに固定長部分が実際に存在するとみなします。
システムカタログキャッシュのコードは、C構造体定義をその固定部分にマップするからです。
したがって、すべての可変長フィールドと、NULLを許容するフィールドは、最後尾に置かれなければならず、また、構造体のフィールドとしてはアクセスできません。
たとえば、pg_type
.typrelid
をNULLにしようとすると、他のコード部分がtypetup->typrelid
を参照しようとして失敗します。(あるいはもっと悪いことにtypetup->typelem
を参照中に失敗します。なぜなら、そのフィールドはtyprelid
の後に来るからです。)
これはランダムなエラーとなるか、あるいはセグメンテーション違反にすらなってしまいます。
As a partial guard against this type of error, variable-length or
nullable fields should not be made directly visible to the C compiler.
This is accomplished by wrapping them in <literal>#ifdef
CATALOG_VARLEN</literal> ... <literal>#endif</literal> (where
<literal>CATALOG_VARLEN</literal> is a symbol that is never defined).
This prevents C code from carelessly trying to access fields that might
not be there or might be at some other offset.
As an independent guard against creating incorrect rows, we
require all columns that should be non-nullable to be marked so
in <structname>pg_attribute</structname>. The bootstrap code will
automatically mark catalog columns as <literal>NOT NULL</literal>
if they are fixed-width and are not preceded by any nullable or
variable-width column.
Where this rule is inadequate, you can force correct marking by using
<literal>BKI_FORCE_NOT_NULL</literal>
and <literal>BKI_FORCE_NULL</literal> annotations as needed.
この種のエラーから部分的に身を守るためには、可変長あるいはNULLを許容するフィールドはCコンパイラから直接見えないようにすべきです。
これは#ifdef CATALOG_VARLEN
... #endif
の中に入れることで達成できます。(ここで、CATALOG_VARLEN
は、決して定義されないシンボルです。)
これにより、Cコードが不注意で存在しないフィールドにアクセスしようとしたり、オフセットが違うフィールドにアクセスしようとするのを防ぐことができます。
不正な行を作るのを防ぐ独立したガードとして、NULLを許容しないすべての列をpg_attribute
でそのように宣言することを要求します。
ブートストラップコードは、固定長で、かつ、NULLを許容したり可変幅である列の次ではないカタログ列に対して自動的にNOT NULL
のマークを付けます。
このルールが不適切なら、BKI_FORCE_NOT_NULL
とBKI_FORCE_NULL
を必要に応じて使ってマーキングを修正できます。
Frontend code should not include any <filename>pg_xxx.h</filename>
catalog header file, as these files may contain C code that won't compile
outside the backend. (Typically, that happens because these files also
contain declarations for functions
in <filename>src/backend/catalog/</filename> files.)
Instead, frontend code may include the corresponding
generated <filename>pg_xxx_d.h</filename> header, which will contain
OID <literal>#define</literal>s and any other data that might be of use
on the client side. If you want macros or other code in a catalog header
to be visible to frontend code, write <literal>#ifdef
EXPOSE_TO_CLIENT_CODE</literal> ... <literal>#endif</literal> around that
section to instruct <filename>genbki.pl</filename> to copy that section
to the <filename>pg_xxx_d.h</filename> header.
フロントエンドのコードはすべての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
にコピーするように指示してください。
A few of the catalogs are so fundamental that they can't even be created
by the <acronym>BKI</acronym> <literal>create</literal> command that's
used for most catalogs, because that command needs to write information
into these catalogs to describe the new catalog. These are
called <firstterm>bootstrap</firstterm> catalogs, and defining one takes
a lot of extra work: you have to manually prepare appropriate entries for
them in the pre-loaded contents of <structname>pg_class</structname>
and <structname>pg_type</structname>, and those entries will need to be
updated for subsequent changes to the catalog's structure.
(Bootstrap catalogs also need pre-loaded entries
in <structname>pg_attribute</structname>, but
fortunately <filename>genbki.pl</filename> handles that chore nowadays.)
Avoid making new catalogs be bootstrap catalogs if at all possible.
少数のカタログは非常に基本的なものなので、ほとんどのカタログで使用されるBKI create
コマンドですら作成できません。そのコマンドが、新しいカタログの記述をこれらのカタログに書き込む必要があるからです。
これらはブートストラップカタログと呼ばれ、定義するためには大量の追加の作業が必要です。
pg_class
とpg_type
のあらかじめロード済みの内容上に手動で適切なエントリを用意し、後のカタログ構造への変更に合わせてそれらのエントリを更新する必要があります。
(また、ブートストラップカタログはpg_attribute
中のロード済みのエントリを必要としますが、幸いにも最近はgenbki.pl
が適切に処理してくれます。)
可能ならば、新しいカタログをブートストラップカタログとして作るのは避けてください。