PostgreSQL数据库集簇初始化——后端接口postgres.bki文件
后端接口postgres.bki文件是在编译的过程中由/src/backend/catalog目录下的脚本程序genbki.sh读取/src/include/catalog目录下的以.h结尾的系统表定义文件(包括系统表索引和TOAST表定义文件)创建,并通常存放在安装树的share子目录下。
在pg_*.h(星号表示对应系统表的名称,每个这样的头文件对应一个系统表的结构定义)的头文件中包含如下内容的定义:定义CATALOG宏,用于以统一的模式去定义系统表的结构以及用以描述系统表的数据结构,如系统表pg_class的定义通过CATALOG(pg_class,1259)来表现。通过宏DATA(x)和DESCR(x)来定义insert操作,这样的Insert操作可能会有多个,用于定义系统表中的初始数据。以pg_class.h为例,其定义了系统relation关系表用于初始化关系表的内容(/src/include/catalog/pg_class.h)。
1 #ifndef PG_CLASS_H 2 #define PG_CLASS_H 3 #include "catalog/genbki.h" 4 /* pg_class definition. cpp turns this into typedef struct FormData_pg_class */ 5 #define RelationRelationId 1259 6 CATALOG(pg_class,1259) BKI_BOOTSTRAP 7 { 8 NameData relname; /* class name */ 9 Oid relnamespace;/* OID of namespace containing this class */ 10 Oid reltype; /* OID of associated entry in pg_type */ 11 Oid relowner; /* class owner */ 12 Oid relam; /* index access method; 0 if not an index */ 13 Oid relfilenode; /* identifier of physical storage file */ 14 Oid reltablespace;/* identifier of table space for relation */ 15 int4 relpages; /* # of blocks (not always up-to-date) */ 16 float4 reltuples; /* # of tuples (not always up-to-date) */ 17 Oid reltoastrelid; /* OID of toast table; 0 if none */ 18 Oid reltoastidxid; /* if toast table, OID of chunk_id index */ 19 bool relhasindex; /* T if has (or has had) any indexes */ 20 bool relisshared; /* T if shared across databases */ 21 bool relistemp; /* T if temporary relation */ 22 char relkind; /* see RELKIND_xxx constants below */ 23 int2 relnatts; /* number of user attributes */ 24 25 /* Class pg_attribute must contain exactly "relnatts" user attributes (with attnums ranging from 1 to relnatts) for this class. It may also contain entries with negative attnums for system attributes. */ 26 int2 relchecks; /* # of CHECK constraints for class */ 27 bool relhasoids; /* T if we generate OIDs for rows of rel */ 28 bool relhaspkey; /* has (or has had) PRIMARY KEY index */ 29 bool relhasrules; /* has (or has had) any rules */ 30 bool relhastriggers; /* has (or has had) any TRIGGERs */ 31 bool relhassubclass; /* has (or has had) derived classes */ 32 TransactionId relfrozenxid; /* all Xids < this are frozen in this rel */ 33 /* VARIABLE LENGTH FIELDS start here. These fields may be NULL, too. NOTE: these fields are not present in a relcache entry's rd_rel field. */ 34 aclitem relacl[1]; /* access permissions */ 35 text reloptions[1]; /* access-method-specific options */ 36 } FormData_pg_class; 37 38 /* Size of fixed part of pg_class tuples, not counting var-length fields */ 39 #define CLASS_TUPLE_SIZE (offsetof(FormData_pg_class,relfrozenxid) + sizeof(TransactionId)) 40 41 /* Form_pg_class corresponds to a pointer to a tuple with the format of pg_class relation. */ 42 typedef FormData_pg_class *Form_pg_class; 43 /* compiler constants for pg_class */ 44 #define Natts_pg_class 25 45 #define Anum_pg_class_relname 1 46 #define Anum_pg_class_relnamespace 2 47 #define Anum_pg_class_reltype 3 48 #define Anum_pg_class_relowner 4 49 #define Anum_pg_class_relam 5 50 #define Anum_pg_class_relfilenode 6 51 #define Anum_pg_class_reltablespace 7 52 #define Anum_pg_class_relpages 8 53 #define Anum_pg_class_reltuples 9 54 #define Anum_pg_class_reltoastrelid 10 55 #define Anum_pg_class_reltoastidxid 11 56 #define Anum_pg_class_relhasindex 12 57 #define Anum_pg_class_relisshared 13 58 #define Anum_pg_class_relistemp 14 59 #define Anum_pg_class_relkind 15 60 #define Anum_pg_class_relnatts 16 61 #define Anum_pg_class_relchecks 17 62 #define Anum_pg_class_relhasoids 18 63 #define Anum_pg_class_relhaspkey 19 64 #define Anum_pg_class_relhasrules 20 65 #define Anum_pg_class_relhastriggers 21 66 #define Anum_pg_class_relhassubclass 22 67 #define Anum_pg_class_relfrozenxid 23 68 #define Anum_pg_class_relacl 24 69 #define Anum_pg_class_reloptions 25 70 71 /* initial contents of pg_class NOTE: only "bootstrapped" relations need to be declared here. Be sure that the OIDs listed here match those given in their CATALOG macros, and that the relnatts values are correct. */ 72 73 /* Note: "3" in the relfrozenxid column stands for FirstNormalTransactionId */ 74 DATA(insert OID = 1247 ( pg_type PGNSP 71 PGUID 0 1247 0 0 0 0 0 f f f r 28 0 t f f f f 3 _null_ _null_ )); 75 DESCR(""); 76 DATA(insert OID = 1249 ( pg_attribute PGNSP 75 PGUID 0 1249 0 0 0 0 0 f f f r 18 0 f f f f f 3 _null_ _null_ )); 77 DESCR(""); 78 DATA(insert OID = 1255 ( pg_proc PGNSP 81 PGUID 0 1255 0 0 0 0 0 f f f r 25 0 t f f f f 3 _null_ _null_ )); 79 DESCR(""); 80 DATA(insert OID = 1259 ( pg_class PGNSP 83 PGUID 0 1259 0 0 0 0 0 f f f r 25 0 t f f f f 3 _null_ _null_ )); 81 DESCR(""); 82 83 #define RELKIND_INDEX 'i' /* secondary index */ 84 #define RELKIND_RELATION 'r' /* ordinary cataloged heap */ 85 #define RELKIND_SEQUENCE 'S' /* SEQUENCE relation */ 86 #define RELKIND_UNCATALOGED 'u' /* temporary heap */ 87 #define RELKIND_TOASTVALUE 't' /* moved off huge values */ 88 #define RELKIND_VIEW 'v' /* view */ 89 #define RELKIND_COMPOSITE_TYPE 'c' /* composite type */ 90 #endif /* PG_CLASS_H */
模板数据库template1是通过运行在bootstrap模式的postgres程序读取postgres.bki文件创建的。BKI文件是一些用特殊语言写的脚本,这些脚本使PostgreSQL后端能够理解,且以特殊的bootstrap模式来执行之,这种模式允许在不存在系统表的零初始条件下执行数据库函数,而普通的SQL命令要求系统表必须存在。因此BKI文件仅用于初始化数据集簇。BKI命令格式如下:
(1) create [bootstrap] [shared_relation] [without_Oids] tablename tableOid (name1 = type1 [, name2=type2, ...]) 创建一个名为tablename并且OID为tableOid的表,表的字段在圆括弧中给出。Bootstrap模式支持下列字段类型:bool、bytea、char、name、int2、int4、regproc、regclass、regtype、text、Oid、tid、xid、cid、int2vector、Oidvector、_int4(数组)、_text(数组)、_Oid(数组)、_char(数组)、_aclitem(数组)。只有在创建完pg_type并且填充了合适的数据之后才可以创建包含其他类型字段的表。如果指定了bootstrap选项,那么将只创建表而不向pg_class等系统表里面插入任何记录。因此这样的表将无法被普通的SQL操作访问,直到系统表中的初始记录用硬方法(BKI的insert命令)插入。这个选项用于创建诸如pg_class等核心的系统表。如果指定了shared_relation选项,那么该表将作为整个数据集簇的共享表创建(比如创建pg_database)。如果指定了without_Oids选项,则该表将不会具有OID字段。
(2) open tablename 打开一个名为tablename的表,准备插入数据。在BKI被执行时,每一个时刻都只有一个表被打开,因此使用open命令时,任何当前已经打开的表都会被关闭。
(3) insert [OID = Oid_value] (value1 value2 ...) 以value1、value2等作为字段值插入一个元组,如果该表具有OID属性,则把Oid_value作为被插入元组的OID。如果Oid_value为零或者省略了OID关键字,将为该插入元组分配系统中可用的下一个OID。
(4) close [tablename] 关闭当前被打开的表。由于每一时刻只有一个表被打开,因此可以省略tablename。
(5) declare [unique] index indexname indexOid on tablename using amname (opclass1 name1 [, ...]) 在名为tablename的表上用amname访问方法创建一个OID为indexOid且名为indexname的索引。索引属性是tablename表的name1、name2等属性,在属性上使用的操作符类分别是opclass1、opclass2等。该命令仅仅是创建一个索引的结构,索引的内容(即索引项)并不由该命令填充。
(6) declare toast toasttableOid toastindexOid on tablename 为名为tablename的表创建一个TOAST表。该TOAST表的OID为toasttableOid,其索引的OID为toastindexOid。与declare index命令一样,该命令也不会填充TOAST表的索引。
(7) build indices 对使用5和6两种命令创建的索引进行内容填充。
在整个源代码被编译时,genbki.sh脚本会被调用,它将从每一个pg_*.h文件中读取系统表定义、系统表的初始化数据、系统表上的索引等信息,然后分别将其转换为对应的BKI命令,最后将所有BKI命令写入postgres.bki文件中,该文件的内容如下:一个create bootstrap命令,用于创建其中一个关键表;一个或多个insert命令,用于填充步骤1创建的关键表中的数据;一个close命令,用于关闭步骤1创建的关键表;重复步骤1-3创建和填充其他关键表;一个不带bootstrap选项的create命令,用于创建一个非关键表;一个open命令,打开非关键表;一个或多个insert命令,填充非关键表所需要的数据;一个close命令,关闭上面打开的非关键表;重复创建其他非关键表;一个或多个declare index命令,用于定义索引;一个build indices命令,用于实际建立上一步所定义的索引。