## 71.1. System Catalog Declaration Rules 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`CATALOG`macro, which so far as the C compiler is concerned is just shorthand for`typedef struct FormData_*`catalogname`*`. Each field in the struct gives rise to a catalog column. Fields can be annotated using the BKI property macros described in`genbki.h`, for example to define a default value for a field or mark it as nullable or not nullable. The`CATALOG`line can also be annotated, with some other BKI property macros described in`genbki.h`, to define other properties of the catalog as a whole, such as whether it is a shared relation. 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`pg_type`.`typrelid`to be NULL, it would fail when some piece of code tried to reference`typetup->typrelid`(or worse,`typetup->typelem`, because that follows`typrelid`)。这将导致随机错误甚至分段违规。 作为对此类错误的部分防护,不应该使可变长度或可为空的字段对 C 编译器直接可见。这是通过将它们包装在`#ifdef CATALOG_VARLEN`...`#万一`(在哪里`CATALOG_VARLEN`是一个从未定义的符号)。这可以防止 C 代码粗心地尝试访问可能不存在或可能位于其他偏移量的字段。作为防止创建错误行的独立防护措施,我们要求将所有不应为空的列标记为`pg_attribute`.引导代码将自动将目录列标记为`非空`如果它们是固定宽度并且前面没有任何可为空或可变宽度的列。如果此规则不充分,您可以通过使用强制正确标记`BKI_FORCE_NOT_NULL`和`BKI_FORCE_NULL`根据需要进行注释。 前端代码不应包含任何`pg_xxx.h`目录头文件,因为这些文件可能包含不会在后端之外编译的 C 代码。(通常,这是因为这些文件还包含函数的声明`src/后端/目录/`文件。)相反,前端代码可能包含相应的生成`pg_xxx_d.h`标头,将包含 OID`#定义`s 和任何其他可能在客户端使用的数据。如果您希望目录标题中的宏或其他代码对前端代码可见,请编写`#ifdef EXPOSE_TO_CLIENT_CODE`...`#万一`围绕该部分进行指导`genbki.pl`将该部分复制到`pg_xxx_d.h`标题。 一些目录是如此基础,以至于它们甚至无法由 BKI 创建`创造`用于大多数目录的命令,因为该命令需要将信息写入这些目录以描述新目录。这些被称为*引导程序*目录,并且定义一个需要很多额外的工作:您必须在预加载的内容中手动为它们准备适当的条目`pg_class`和`pg_type`,并且这些条目将需要更新以用于目录结构的后续更改。(引导目录也需要在`pg_attribute`, 但幸运的是`genbki.pl`现在可以处理这些琐事。)尽可能避免使新目录成为引导目录。