2024年9月26日: PostgreSQL 17 发布!
支持的版本:当前 (17) / 16 / 15 / 14 / 13 / 12
开发版本:devel
不支持的版本:11

67.1. 系统目录声明规则 #

目录头文件的主要部分是 C 结构体定义,描述了目录中每一行的布局。这以 CATALOG 宏开头,就 C 编译器而言,它只是 typedef struct FormData_catalogname 的简写。结构体中的每个字段都会产生一个目录列。可以使用 genbki.h 中描述的 BKI 属性宏来注释字段,例如,为字段定义默认值或将其标记为可空或不可空。 CATALOG 行也可以使用 genbki.h 中描述的其他一些 BKI 属性宏进行注释,以定义整个目录的其他属性,例如它是否是共享关系。

系统目录缓存代码(以及大多数目录修改代码)假设所有系统目录元组的固定长度部分实际上都存在,因为它将此 C 结构体声明映射到它们。因此,所有可变长度字段和可空字段都必须放在最后,并且不能作为结构体字段访问。例如,如果您尝试将 pg_type.typrelid 设置为 NULL,则当某些代码尝试引用 typetup->typrelid(或更糟的是 typetup->typelem,因为它在 typrelid 之后)时会失败。这将导致随机错误,甚至段错误。

作为对此类错误的部分防护措施,可变长度或可空字段不应直接对 C 编译器可见。这是通过将它们包装在 #ifdef CATALOG_VARLEN ... #endif 中来实现的(其中 CATALOG_VARLEN 是一个永远不会定义的符号)。这可以防止 C 代码不小心尝试访问可能不存在或可能位于其他偏移量的字段。作为防止创建不正确行的独立防护措施,我们要求所有应为不可空的列在 pg_attribute 中都被标记为不可空。如果列是固定宽度的并且前面没有可空或可变宽度的列,则引导程序代码会自动将目录列标记为 NOT NULL。如果此规则不适用,您可以根据需要使用 BKI_FORCE_NOT_NULLBKI_FORCE_NULL 注释强制进行正确的标记。

前端代码不应包含任何 pg_xxx.h 目录头文件,因为这些文件可能包含在后端之外无法编译的 C 代码。(通常,这是因为这些文件还包含 src/backend/catalog/ 文件中函数的声明。)相反,前端代码可以包含相应的生成的 pg_xxx_d.h 头文件,该头文件将包含 OID #define 和客户端可能使用的任何其他数据。如果您希望目录头文件中的宏或其他代码对前端代码可见,请在该部分周围编写 #ifdef EXPOSE_TO_CLIENT_CODE ... #endif,以指示 genbki.pl 将该部分复制到 pg_xxx_d.h 头文件。

一些目录非常基础,甚至无法通过BKI 大多数目录使用的 create 命令创建,因为该命令需要将信息写入这些目录以描述新目录。这些被称为引导目录,定义一个引导目录需要额外的工作:您必须手动为 pg_classpg_type 的预加载内容中准备相应的条目,并且这些条目需要针对目录结构的后续更改进行更新。(引导目录还需要在 pg_attribute 中预加载条目,但幸运的是,genbki.pl 现在处理这项工作。)如果可能,请避免将新目录设为引导目录。

提交更正

如果您在文档中看到任何不正确的内容,与您对特定功能的体验不符,或者需要进一步澄清,请使用此表单报告文档问题。