欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Postgresql数据库新增一张系统表

程序员文章站 2022-06-11 21:17:36
...

在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
}

注意:

  1. 字段顺序要和index中顺序相对应,和表字段顺序没关系
  2. 好像最多就支持4个字段。因为SearchSysCache等函数 最多就支搜4个字段
  3. 如果有多个索引,取其中一个索引就可以, 不要求必须是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为例