Postgresql数据库新增一张系统表
在catalog 的makefile 中添加相应的系统表头文件
./src/backend/catalog/Makefile:42: pg_foreign_table.h pg_partition_key.h \
建表
– 以pg_partition_key为例,给该表添加代码pg_partition_key.h
在include的 catalog目录下添加这张表的定义
CATALOG宏定义为#define CATALOG(name,oid,oidmacro) typedef struct CppConcat(FormData_,name)
,定义在src/include/catalog/genbki.h中。所以这里的结构体为typedef struct FormData_pg_partition_key
#ifndef PG_PARTITION_KEY_H
#define PG_PARTITION_KEY_H
#include "catalog/genbki.h"
#define PartitionKeyRelationId 3180
CATALOG(pg_partition_key,3180) BKI_WITHOUT_OIDS
{
Oid pkrelid;
int16 pkattnum;
} FormData_pg_partition_key;
typedef FormData_pg_partition_key *Form_pg_partition_key;
#define Natts_pg_partition_key 2
#define Anum_pg_partition_key_pkrelid 1
#define Anum_pg_partition_key_pkattnum 2
#endif
在catalog 的indexing.h 头文件中添加系统表的唯一性索引
DECLARE_UNIQUE_INDEX(pg_partition_key_relid_index, 3181, on pg_partition_key using btree(pkrelid oid_ops));
#define PartitionKeyRelidIndexId 3181
Syscache
– 以 pg_partion_key为例
首先要在syscache.h中添加 SysCacheIdentifier
要在syscache.c 的 cacheinfo[] 中添加这张表
cache的定义:
struct cachedesc{
Oid reloid;
Oid indoid;
int nkeys;
int key[4];
int nbuckets;
};
仿造它添加条目
{PartitionKeyRelationId,
PartitionKeyRelidIndexId,
1,
{
Anum_pg_partition_key_pkrelid,
0,
0,
0
},
128
}
注意:
- 字段顺序要和index中顺序相对应,和表字段顺序没关系
- 好像最多就支持4个字段。因为SearchSysCache等函数 最多就支搜4个字段
- 如果有多个索引,取其中一个索引就可以, 不要求必须是unique索引
执行syscache 进行查找
void GetPartitionKeyInfo(Oid pkrelid, int16 *attnum){
Form_pg_partition_key form_pk;
HeapTuple tuple;
Assert(attnum);
if (!OidIsValid(pkrelid))
return ;
tuple = SearchSysCache1((int)PARTITIONKEYREL, ObjectIdGetDatum(pkrelid));
if (!HeapTupleIsValid(tuple))
ereport(ERROR,(errmsg("Can not find partition key of relation(%u).",pkrelid)));
Assert(tuple != NULL);
form_pk = (Form_pg_partition_key)GETSTRUCT(tuple);
*attnum = form_pk->pkattnum;
ReleaseSysCache(tuple);
}
执行syscache进行多行查找
bool result = false;
CatCList *catlist;
int i;
catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno));
for (i = 0; i < catlist->n_members; i++) {
HeapTuple tuple = &catlist->members[i]->tuple;
Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
if (aform->amopmethod != BTREE_AM_OID)
continue;
if (aform->amopstrategy == BTLessStrategyNumber || aform->amopstrategy == BTGreaterStrategyNumber) {
if (aform->amoplefttype == aform->amoprighttype) {
*opfamily = aform->amopfamily;
*opcintype = aform->amoplefttype;
*strategy = aform->amopstrategy;
result = true;
break;
}
}
}
注意: SearchSysCacheList1 函数查找的字段数要少于index的字段数。
打开系统表的方式
用heap_open的方式打开系统表,用这种方式可以比较方便的动态插入和删除
用heapopen方式打开系统表/用户表,还可以用heap_open的方式打开系统表,例如seclable.c中的部分:
pg_seclabel = heap_open(SecLabelRelationId, RowExclusiveLock);
scan = systable_beginscan(pg_seclabel, SecLabelObjectIndexId, true, SnapshotNow, 4, keys);
oldtup = systable_getnext(scan);
if (HeapTupleIsValid(oldtup)) {
if (label == NULL)
simple_heap_delete(pg_seclabel, &oldtup->t_self);
else{
replaces[Anum_pg_seclabel_label - 1] = true;
newtup = heap_modify_tuple(oldtup, RelationGetDescr(pg_seclabel), values, nulls, replaces);
simple_heap_update(pg_seclabel, &oldtup->t_self, newtup);
}
}
systable_endscan(scan);
if (newtup == NULL && label != NULL){
newtup = heap_form_tuple(RelationGetDescr(pg_seclabel),values, nulls);
simple_heap_insert(pg_seclabel, newtup);
}
if (newtup != NULL){
CatalogUpdateIndexes(pg_seclabel, newtup);
heap_freetuple(newtup);
}
heap_close(pg_seclabel, RowExclusiveLock);
从heaptuple中获取datum 的方法(这两个方法不仅适用于syscache,而且适用于一般的heap表)
方法1
pg_seclabel = heap_open(SecLabelRelationId, AccessShareLock);
scan = systable_beginscan(pg_seclabel, SecLabelObjectIndexId, true, SnapshotNow, 4, keys);
tuple = systable_getnext(scan);
if (HeapTupleIsValid(tuple)) {
datum = heap_getattr(tuple, Anum_pg_seclabel_label, RelationGetDescr(pg_seclabel), &isnull);
if (!isnull) seclabel = TextDatumGetCString(datum);
}
systable_endscan(scan);
heap_close(pg_seclabel, AccessShareLock);
方法2
对于text 和 bytea,从系统缓存中获取不宜采用Form_xxx->yyy这种方法,而适合采用SysCacheGetAttr 方法
例如获取fdw options的:
datum = SysCacheGetAttr(FOREIGNDATAWRAPPEROID,
tp,
Anum_pg_foreign_data_wrapper_fdwoptions,
&isnull);
SysCacheGetAttr 调用了 heap_getattr
方法3
还有一个方法也是类似
datum = fastgetattr(tuple,
Anum_pg_class_reloptions,
tupdesc,
&isnull);
其中tupdesc 可以通过 RelationGetDescr(pg_seclabel) 获得
SysCacheGetAttr 调用了 heap_getattr
heap_getattr 本质上也是调用了 fastgetattr 和 heap_getsysattr,
heap_getattr 更通用,不光可以针对系统表, 也可以针对用户表
其他要注意的地方:
initdb的问题
问题描述:
initdb -E UTF-8 -D ~/database6 --locale=en_US.UTF8 -U postgres -W
在initdb的时候,出现错误:
(gdb) FATAL: type 17 not supported as catcache key
catcache.c: 162
(发现是在执行这个命令的时候:/home/hl/uda_new/cplusplus/ci/postgres/bin/postgres" --single -F -O -c search_path=pg_catalog -c exit_on_error=true template1但这个命令又不能单独执行,不管他)
这个是因为BYTEAOID 没有指定hash函数和等值函数,解决的办法就是在这个函数中把BYTEAOID添加上(bytea和text本质上存储格式是相通的,所以这样改没有太大问题)
static void GetCCHashEqFuncs(Oid keytype, PGFunction *hashfunc, RegProcedure *eqfunc){
...
case TEXTOID:
case BYTEAOID:
*hashfunc = hashtext;
*eqfunc = F_TEXTEQ;
...
}
SysCache 使用的问题
SysCacheGetAttr(DATASRCCFGREL,
tuple,
Anum_pg_data_src_cfg_datasrckind,
&isNull);
使用syscache的地方。第一个参数是在 syscache.h中的enum SysCacheIdentifier 中的id,而不是OID
查找系统缓存的问题
ERROR: could not determine which collation to use for string comparison
HINT: Use the COLLATE clause to set the collation explicitly.
这个是index和 syscache.c 中定义的字段对不上
建议新增系统表的时候,在查找字段上定义为NameData 而不要定义为Text, 否则查找很成问题
以Postgresql9.3.5为例
下一篇: Oracle数据库的导入导出