69.1. 系统目录声明规则

目录头文件的关键部分是 C 结构定义,它描述目录的每一行的布局。它以CATALOG宏开头,就 C 编译器而言,它只是typedef struct FormData_catalogname的简写。结构中的每个字段都会产生一个目录列。可以使用genbki.h中描述的 BKI 属性宏对字段进行 Comments,例如,定义字段的默认值或将其标记为可为空或不可为空。 CATALOG行也可以用genbki.h中描述的其他 BKI 属性宏进行 Comments,以定义整个目录的其他属性,例如是否具有 OID(默认情况下,它具有 OID)。

系统目录高速缓存代码(通常是大多数使用目录的代码)通常假定所有系统目录 Tuples 的固定长度部分均已存在,因为它将此 C 结构声明 Map 到它们上。因此,所有可变长度字段和可为空的字段必须放在末尾,并且不能将它们作为结构字段访问。例如,如果您尝试设置pg_typetyprelid为 NULL,当某段代码尝试引用typetup->typrelid(或更糟糕的是typetup->typelem,因为它紧随typrelid)时,它将失败。这将导致随机错误,甚至会导致细分违规。

作为防止此类错误的部分保护措施,可变长度或可为空的字段不应对 C 编译器直接可见。通过将它们包装在#ifdef CATALOG_VARLEN ... #endif(其中CATALOG_VARLEN是从未定义的符号)中来实现。这样可以防止 C 代码粗心地尝试访问可能不存在或可能存在其他偏移量的字段。为了防止创建不正确的行,我们要求将所有不可为空的列都标记为pg_attribute。引导代码将自动将目录列标记为NOT NULL,如果它们是固定宽度的,并且没有可空列的前面。如果该规则不足,则可以根据需要使用BKI_FORCE_NOT_NULLBKI_FORCE_NULLComments 来强制进行正确的标记。但是请注意,仅在执行程序中强制执行NOT NULL约束,而不是针对由随机 C 代码生成的 Tuples 执行约束,因此在手动创建或更新目录行时仍需要谨慎。

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

一些目录是如此基础,以至于大多数目录都无法使用 BKI create命令来创建它们,因为该命令需要将信息写入这些目录中以描述新目录。这些称为* bootstrap *目录,定义一个目录需要进行大量额外的工作:您必须在pg_classpg_type的预加载内容中为它们手动准备适当的条目,并且需要对这些条目进行更新以用于后续的更改目录的结构。 (Bootstrap 目录还需要在pg_attribute中预加载条目,但是幸运的是genbki.pl现在处理了繁琐的工作.)尽可能避免将新目录作为 Bootstrap 目录。

上一章 首页 下一章