Postgresql 中文操作指南

75.1. System Catalog Declaration Rules #

目录头文件的重要部分是 C 结构定义,它描述了目录的每一行的布局。这以 CATALOG 宏开始,它与 C 编译器相关,仅是 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 的简写形式,例如定义字段的默认值或将其标记为可为空或不可为空。 CATALOG 行还可以使用 genbki.h 中所述的其他一些 BKI 属性宏进行注释,以定义整个目录的其他属性,例如它是否为共享关系。

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 FormDatacatalogname. 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.

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

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). This would result in random errors or even segmentation violations.

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

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 #ifdef CATALOG_VARLEN …​ #endif (where CATALOG_VARLEN 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 pg_attribute. The bootstrap code will automatically mark catalog columns as NOT NULL 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 BKI_FORCE_NOT_NULL and BKI_FORCE_NULL annotations as needed.

前端代码不应包含任何 pg_xxx.h 目录头文件,因为这些文件可能包含在后端之外无法编译的 C 代码。(通常,这是因为这些文件还包含 src/backend/catalog/ 文件中的函数声明)。相反,前端代码可以包含相应的生成 pg_xxx_d.h 头,其中将包含 OID #define_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 _#ifdef EXPOSE_TO_CLIENT_CODE …​ #endif 围绕该部分以指示 genbki.pl 将该部分复制到 pg_xxx_d.h 头。

Frontend code should not include any pg_xxx.h 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 src/backend/catalog/ files.) Instead, frontend code may include the corresponding generated pg_xxx_d.h header, which will contain OID #define_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 _#ifdef EXPOSE_TO_CLIENT_CODE …​ #endif around that section to instruct genbki.pl to copy that section to the pg_xxx_d.h header.

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

A few of the catalogs are so fundamental that they can’t even be created by the BKI create 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 bootstrap 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 pg_class and pg_type, and those entries will need to be updated for subsequent changes to the catalog’s structure. (Bootstrap catalogs also need pre-loaded entries in pg_attribute, but fortunately genbki.pl handles that chore nowadays.) Avoid making new catalogs be bootstrap catalogs if at all possible.