Postgresql 中文操作指南
75.2. System Catalog Initial Data #
任何手动创建的初始数据(有些没有)的目录都对应一个 .dat 文件,该文件以可编辑的格式包含其初始数据。
75.2.1. Data File Format #
每个 .dat 文件都包含 Perl 数据结构文字,这些文字可以被简单地求值以产生一个由哈希引用的数组组成内存中的数据结构,每个数组对应一个目录行。从 pg_database.dat 稍作修改的摘录将演示关键功能:
[
# A comment could appear here.
{ oid => '1', oid_symbol => 'Template1DbOid',
descr => 'database\'s default template',
datname => 'template1', encoding => 'ENCODING',
datlocprovider => 'LOCALE_PROVIDER', datistemplate => 't',
datallowconn => 't', datconnlimit => '-1', datfrozenxid => '0',
datminmxid => '1', dattablespace => 'pg_default', datcollate => 'LC_COLLATE',
datctype => 'LC_CTYPE', daticulocale => 'ICU_LOCALE', datacl => '_null_' },
]
需要指出的是:
75.2.2. OID Assignment #
可以通过编写 oid ⇒ _nnnn _ metadata field. Furthermore, if an OID is assigned, a C macro for that OID can be created by writing an _oid_symbol ⇒ _name 元数据字段来给数据中出现的编目行赋予一个手动指定的 OID。
如果预加载的目录行有其他预加载的行对其引用的 OID,那么它必须有预分配的 OID。如果行的 OID 必须由 C 代码引用,那么还需要预分配的 OID。如果以上情况均不适用,则 oid 元数据字段可以被省略,这种情况下,引导代码会自动分配一个 OID。实际上,即使给定的目录中只有部分行实际上存在交叉引用,我们通常会对所有或没有预加载行的 OID 进行预分配。
在 C 代码中编写任何 OID 的实际数值被认为是非常不好的行为;相反,请始终使用宏。对 pg_proc OID 的直接引用非常普遍,以至于有一种特殊机制可以自动创建必要的宏;请参阅 src/backend/utils/Gen_fmgrtab.pl。同样地,但出于历史原因,采用非相同的方式,有一种自动方法可以创建 pg_type OID 的宏。因此,在上述两个目录中,没有 oid_symbol 项。同样,对于系统目录和索引的 pg_class OID 的宏会自动设置。对于所有其他系统目录,您必须通过 oid_symbol 项手动指定需要的任何宏。
要查找可用于新预加载行的可用 OID,请运行 src/include/catalog/unused_oids 脚本。它会打印未使用的 OID 的包含范围(例如,输出行 45-900 表示尚未分配 OID 45 到 900)。目前,OID 1–9999 保留手工分配;unused_oids 脚本只需浏览目录标头和 .dat 文件,即可查看哪些未出现。您还可以使用 duplicate_oids 脚本来检查错误。(genbki.pl 将为任何未手动分配 OID 的行分配 OID,它还将检测编译时重复的 OID。)
当选择不太可能立即提交的补丁的 OID 时,最佳做法是使用一组或多或少连续的 OID,从范围内随机选择的 8000—9999 开始。这会尽可能降低与同时开发的其他补丁产生 OID 冲突的风险。为了保持 8000—9999 范围可用于开发目的,在某个补丁提交到主 git 存储库之后,应将其 OID 重新编号到该范围内的可用空间。通常,这会在每个开发周期接近结束时进行,同时移动该周期中提交的补丁所消耗的所有 OID。可以将脚本 renumber_oids.pl 用于此目的。如果发现未提交补丁与最近提交的某些补丁存在 OID 冲突,renumber_oids.pl 也可以用于恢复该情况。
由于有可能重新编号补丁分配的 OID 的惯例,补丁分配的 OID 在该补丁包含在正式发布版本中之前不应被视为稳定。然而,一旦发布,我们不会更改手动分配的对象 OID,因为那会产生各种兼容性问题。
如果 genbki.pl 需要为没有手动分配的 OID 的目录条目分配一个 OID,它将使用 10000—11999 范围内的值。服务器的 OID 计数器在引导运行开始时设置为 10000,因此在引导处理过程中动态创建的任何对象也会在此范围内接收 OID。(通常的 OID 分配机制负责防止任何冲突。)
OID 低于 FirstUnpinnedObjectId(12000)的对象被认为是“固定的”,防止它们被删除。(有少量的例外情况,它们是硬编码到 IsPinnedObject() 中。)initdb 强制 OID 计数器上升到 FirstUnpinnedObjectId,一旦它准备创建未固定的对象。因此,在 initdb 后期创建的对象(例如,在运行 information_schema.sql 脚本时创建的对象)不会被固定,而 genbki.pl 中已知的所有对象都会被固定。
正常数据库操作过程中分配的 OID 限制为 16384 或更高。这确保了 10000—16383 范围可用于自动分配的 OID genbki.pl 或在 initdb 期间分配的 OID。这些自动分配的 OID 不被认为稳定,并且可能因安装而异。
75.2.3. OID Reference Lookup #
原则上,从一个初始目录行到另一个初始目录行的交叉引用可以通过在引用字段中写入被引用行的预分配 OID 来写。但是,这违背了项目的策略,因为它容易出错、难以阅读,并且如果重新编号了新分配的 OID,则容易损坏。因此 genbki.pl 提供机制来编写符号引用。规则如下:
genbki.pl 在运行时解析所有符号引用,并将简单的数字 OID 放入发出的 BKI 文件中。因此,引导后端无需处理符号引用。
即使目录没有需要查找的初始数据,使用 BKI_LOOKUP 或 BKI_LOOKUP_OPT 标记 OID 引用列也是很有必要的。这允许 genbki.pl 记录存在于系统目录中的外键关系。该信息用于回归测试中,以检查不正确的条目。另请参阅宏 DECLARE_FOREIGN_KEY、DECLARE_FOREIGN_KEY_OPT、DECLARE_ARRAY_FOREIGN_KEY 和 DECLARE_ARRAY_FOREIGN_KEY_OPT,它们用于声明对 BKI_LOOKUP 来说过于复杂的复杂外键关系(通常是多列外键关系)。
75.2.4. Automatic Creation of Array Types #
大部分标量数据类型应该有相应的数组类型(即,标准元素类型是标量类型的可变长度数组类型,并且由标量类型的 pg_type 条目的 typarray 字段引用)。genbki.pl 在大多数情况下能够自动生成数组类型的 pg_type 条目。
要使用此设施,只需在标量类型的 pg_type 中填写 array_type_oid ⇒ _nnnn_ 元数据字段,并指定用于数组类型 的 OID 即可。您随后可以忽略 typarray 字段,因为它会自动使用该 OID 进行填充。
生成的数组类型的名称是标量类型的名称,前面加上下划线。数组条目的其他字段由 pg_type.h 中的 BKI_ARRAY_DEFAULT(_value) 注释填充,如果没有注释,则从标量类型复制。(对于 typalign 还有一个特殊情况。)然后将两个条目的 typelem 和 typarray 字段设置为交叉引用彼此。
75.2.5. Recipes for Editing Data Files #
以下是一些关于在更新目录数据文件时执行常见任务的最简单方法的建议。
*Add a new column with a default to a catalog: * 使用 BKI_DEFAULT(_value) 注释将列添加到标头文件。数据文件只需要通过在现有行中添加需要非默认值来调整字段即可。
*Add a default value to an existing column that doesn’t have one: * 向标头文件添加 BKI_DEFAULT 注释,然后运行 make reformat-dat-files 以删除现在冗余的字段条目。
*Remove a column, whether it has a default or not: * 从标头中删除列,然后运行 make reformat-dat-files 以删除现在无用的字段条目。
*Change or remove an existing default value: * 您不能简单地更改标头文件,因为那样会导致错误解释当前数据。首先运行 make expand-dat-files 用明确插入的所有默认值重写数据文件,然后更改或删除 BKI_DEFAULT 注释,然后再次运行 make reformat-dat-files 以删除多余的字段。
*Ad-hoc bulk editing: * reformat_dat_file.pl 可以适应执行多种批量更改。查找显示可以在其中插入一次性代码的块注释。在以下示例中,我们将 pg_proc 中的两个布尔字段合并到一个字符字段中:
有关用于批量编辑的脚本的更多示例,请参阅附加到此邮件的 convert_oid2name.pl 和 remove_pg_type_oid_symbols.pl : link:https://www.postgresql.org/message-id/CAJVSVGVX8gXnPm+Xa= DxR7kFYprcQ1tNcCT5D0O3ShfnM6jehA@mail.gmail.com[ link:https://www.postgresql.org/message-id/CAJVSVGVX8gXnPm+Xa= DxR7kFYprcQ1tNcCT5D0O3ShfnM6jehA@mail.gmail.com]