PostgreSQL 内核开发练习

Stella981
• 阅读 672

代码版本: postgresql-10.1

一、直接写入内核代码

1.创建系统表

修改postgres.bki文件,添加创建系统表语句

create pg_subscription_rel 6102 without_oids
 (
 srsubid = oid ,
 srrelid = oid ,
 srsubstate = char ,
 srsublsn = pg_lsn
 )
open pg_subscription_rel
close pg_subscription_rel
# by sunbeau
create sunbeau_droprecord 88889
 (
 tableiod = oid ,
 tablename = name ,
 namespaceid = oid ,
 ownerid = oid
 )
open sunbeau_droprecord
close sunbeau_droprecord
declare toast 2830 2831 on pg_attrdef
declare toast 2832 2833 on pg_constraint
declare toast 2834 2835 on pg_description
2. 修改 tablecmd.c 文件

1)添加头文件

#include "libpq-fe.h" //直接添加头文件编译会找不到,可以使用 /xxx/src/interfaces/libpq/libpq-fe.h 绝对路径

或者修改 src/backend/commands/Makefile
添加

override CPPFLAGS := -I. -I$(libpq_srcdir) $(CPPFLAGS)

2)添加两个函数

Oid
MyGetOwnerId(Oid class_oid)
{
    HeapTuple    tuple;
    Oid            ownerId;

    tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(class_oid));
    if (!HeapTupleIsValid(tuple))
        ereport(ERROR,
                (errcode(ERRCODE_UNDEFINED_TABLE),
                 errmsg("relation with OID %u does not exist", class_oid)));

    ownerId = ((Form_pg_class) GETSTRUCT(tuple))->relowner;

    ReleaseSysCache(tuple);
    return ownerId;
}

static
void Write_info(Oid tableOid,char * tableName,Oid NameSpaceId,Oid Ownid)
{
    char conninfo[256];
    char SQL[256];

    PGconn *conn = NULL;
    PGresult   *res;
    char * DBname;
    char * Username; 

    DBname = get_database_name(MyDatabaseId);
    // Username = GetUserNameFromId(GetUserId(), true);
    Username = GetUserNameFromId(10, true); // 10 speruser
    sprintf(conninfo, "dbname = %s user = %s", DBname, Username);
    sprintf(SQL, "insert into sunbeau_droprecord values(%d,\'%s\',%d,%d);", tableOid, tableName, NameSpaceId, Ownid);
    conn = PQconnectdb(conninfo);
    if (PQstatus(conn) != CONNECTION_OK)
    {
        printf("Connection to database failed");
    }
    res = PQexec(conn,SQL);
    PQclear(res);
    PQfinish(conn);
}

3)修改RemoveRelations函数

/*
 * RemoveRelations
 *        Implements DROP TABLE, DROP INDEX, DROP SEQUENCE, DROP VIEW,
 *        DROP MATERIALIZED VIEW, DROP FOREIGN TABLE
 */
void
RemoveRelations(DropStmt *drop)
{
    ObjectAddresses *objects;
    char        relkind;
    ListCell   *cell;
    int            flags = 0;
    LOCKMODE    lockmode = AccessExclusiveLock;

    /* DROP CONCURRENTLY uses a weaker lock, and has some restrictions */
    if (drop->concurrent)
    {
        flags |= PERFORM_DELETION_CONCURRENTLY;
        lockmode = ShareUpdateExclusiveLock;
        Assert(drop->removeType == OBJECT_INDEX);
        if (list_length(drop->objects) != 1)
            ereport(ERROR,
                    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                     errmsg("DROP INDEX CONCURRENTLY does not support dropping multiple objects")));
        if (drop->behavior == DROP_CASCADE)
            ereport(ERROR,
                    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                     errmsg("DROP INDEX CONCURRENTLY does not support CASCADE")));
    }

    /*
     * First we identify all the relations, then we delete them in a single
     * performMultipleDeletions() call.  This is to avoid unwanted DROP
     * RESTRICT errors if one of the relations depends on another.
     */

    /* Determine required relkind */
    switch (drop->removeType)
    {
        case OBJECT_TABLE:
            relkind = RELKIND_RELATION;
            break;

        case OBJECT_INDEX:
            relkind = RELKIND_INDEX;
            break;

        case OBJECT_SEQUENCE:
            relkind = RELKIND_SEQUENCE;
            break;

        case OBJECT_VIEW:
            relkind = RELKIND_VIEW;
            break;

        case OBJECT_MATVIEW:
            relkind = RELKIND_MATVIEW;
            break;

        case OBJECT_FOREIGN_TABLE:
            relkind = RELKIND_FOREIGN_TABLE;
            break;

        default:
            elog(ERROR, "unrecognized drop object type: %d",
                 (int) drop->removeType);
            relkind = 0;        /* keep compiler quiet */
            break;
    }

    /* Lock and validate each relation; build a list of object addresses */
    objects = new_object_addresses();

    foreach(cell, drop->objects)
    {
        RangeVar   *rel = makeRangeVarFromNameList((List *) lfirst(cell));
        Oid            relOid;
        ObjectAddress obj;
        struct DropRelationCallbackState state;

        /*
         * These next few steps are a great deal like relation_openrv, but we
         * don't bother building a relcache entry since we don't need it.
         *
         * Check for shared-cache-inval messages before trying to access the
         * relation.  This is needed to cover the case where the name
         * identifies a rel that has been dropped and recreated since the
         * start of our transaction: if we don't flush the old syscache entry,
         * then we'll latch onto that entry and suffer an error later.
         */
        AcceptInvalidationMessages();

        /* Look up the appropriate relation using namespace search. */
        state.relkind = relkind;
        state.heapOid = InvalidOid;
        state.partParentOid = InvalidOid;
        state.concurrent = drop->concurrent;
        relOid = RangeVarGetRelidExtended(rel, lockmode, true,
                                          false,
                                          RangeVarCallbackForDropRelation,
                                          (void *) &state);


        /* Not there? */
        if (!OidIsValid(relOid))
        {
            DropErrorMsgNonExistent(rel, relkind, drop->missing_ok);
            continue;
        }

        /* OK, we're ready to delete this one */
        obj.classId = RelationRelationId;
        obj.objectId = relOid;
        obj.objectSubId = 0;

        add_exact_object_address(&obj, objects);
        Write_info(relOid,rel->relname,RangeVarGetCreationNamespace(rel),MyGetOwnerId(relOid)); // add by sunbeau

    }
    
    
    performMultipleDeletions(objects, drop->behavior, flags);

    free_object_addresses(objects);
}
3. 修改 src/backend/Makefile 文件
LIBS += -L$(top_builddir)/src/interfaces/libpq -lpq

PostgreSQL 内核开发练习

4.进入src/interfaces/libpq 编译文件

在编译链接src/backend/下的postgres程序时,libpq库文件还没有编译会报错,所以需要先进行本步骤先编译

cd src/interfaces/libpq
make
5.编译安装数据库

返回源代码根目录编译安装

make ; make install
6.测试

PostgreSQL 内核开发练习

二、使用插件

1.创建系统表

同一 略

2.添加自定义hook

1)修改 tablecmd.h 文件

typedef void (*TableDropRecord_hook_type) (Oid tableOid,char * tableName,Oid NameSpaceId,Oid Ownid);

extern PGDLLIMPORT TableDropRecord_hook_type TableDropRecord_hook;

2)修改 tablecmd.c 文件

#include "utils/snapmgr.h"
#include "utils/syscache.h"
#include "utils/tqual.h"
#include "utils/typcache.h"


TableDropRecord_hook_type TableDropRecord_hook = NULL; // add by sunbeau

/*
 * ON COMMIT action list
 */
typedef struct OnCommitItem
{
        Oid                     relid;                  /* relid of relation */
        OnCommitAction oncommit;        /* what to do at end of xact */

【1】添加MyGetOwnerId函数,同一 。
【2】修改RemoveRelations函数,将一中的Write_info调用函数去掉

// Write_info(relOid,rel->relname,RangeVarGetCreationNamespace(rel),MyGetOwnerId(relOid)); // add by sunbeau
if (TableDropRecord_hook) // add by sunbeau
{
    (*TableDropRecord_hook)(relOid,rel->relname,RangeVarGetCreationNamespace(rel),MyGetOwnerId(relOid));
}
3.编写插件

1)postgresql-10.1/contrib 文件目录下创建 droprecord 目录
2)创建Makefile

# contrib/droprecord/Makefile

#MODULES = droprecord
MODULE_big = droprecord
OBJS = droprecord.o $(WIN32RES)
PGFILEDESC = "droprecord"
PG_CPPFLAGS = -I$(libpq_srcdir)
SHLIB_LINK = $(libpq)

ifdef USE_PGXS
PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)
include $(PGXS)
else
subdir = contrib/droprecord
top_builddir = ../..
include $(top_builddir)/src/Makefile.global
include $(top_srcdir)/contrib/contrib-global.mk
endif

3)创建droprecord.c

#include <stdio.h>  
#include <stdlib.h>  
#include <string.h> 

#include "postgres.h"
#include "miscadmin.h"
#include "nodes/parsenodes.h"
#include "nodes/pg_list.h"
#include "catalog/pg_class.h"
#include "executor/executor.h"
#include "tcop/utility.h"
#include "postgres.h"

#include "access/htup_details.h"
#include "access/reloptions.h"
#include "access/twophase.h"
#include "access/xact.h"
#include "access/xlog.h"
#include "catalog/catalog.h"
#include "catalog/namespace.h"
#include "catalog/toasting.h"
#include "commands/alter.h"
#include "commands/async.h"
#include "commands/cluster.h"
#include "commands/comment.h"
#include "commands/collationcmds.h"
#include "commands/conversioncmds.h"
#include "commands/copy.h"
#include "commands/createas.h"
#include "commands/dbcommands.h"
#include "commands/defrem.h"
#include "commands/discard.h"
#include "commands/event_trigger.h"
#include "commands/explain.h"
#include "commands/extension.h"
#include "commands/matview.h"
#include "commands/lockcmds.h"
#include "commands/policy.h"
#include "commands/portalcmds.h"
#include "commands/prepare.h"
#include "commands/proclang.h"
#include "commands/schemacmds.h"
#include "commands/seclabel.h"
#include "commands/sequence.h"
#include "commands/tablecmds.h"
#include "commands/tablespace.h"
#include "commands/trigger.h"
#include "commands/typecmds.h"
#include "commands/user.h"
#include "commands/vacuum.h"
#include "commands/view.h"
#include "miscadmin.h"
#include "parser/parse_utilcmd.h"
#include "postmaster/bgwriter.h"
#include "rewrite/rewriteDefine.h"
#include "rewrite/rewriteRemove.h"
#include "storage/fd.h"
#include "tcop/pquery.h"
#include "tcop/utility.h"
#include "utils/acl.h"
#include "utils/guc.h"
#include "utils/syscache.h"
#include "libpq-fe.h"

PG_MODULE_MAGIC;

void _PG_init(void);
void _PG_fini(void);

static TableDropRecord_hook_type prev_TableDropRecord_hook = NULL;

static
void
TableDropRecord(Oid tableOid,char * tableName,Oid NameSpaceId,Oid Ownid)
{
    char conninfo[256];
    char SQL[256];

    PGconn *conn = NULL;
    PGresult   *res;
    char * DBname;
    char * Username; 

    DBname = get_database_name(MyDatabaseId);
    // Username = GetUserNameFromId(GetUserId(), true);
    Username = GetUserNameFromId(10, true); // 10 speruser
    sprintf(conninfo, "dbname = %s user = %s", DBname, Username);
    sprintf(SQL, "insert into sunbeau_droprecord values(%d,\'%s\',%d,%d);", tableOid, tableName, NameSpaceId, Ownid);
    conn = PQconnectdb(conninfo);
    if (PQstatus(conn) != CONNECTION_OK)
    {
        printf("Connection to database failed");
    }
    res = PQexec(conn,SQL);
    PQclear(res);
    PQfinish(conn);
}

// Install Hook
void
_PG_init(void)
{
        prev_TableDropRecord_hook = TableDropRecord_hook;
        TableDropRecord_hook = TableDropRecord;
}


// Uninstall Hook
void
_PG_fini(void)
{
        TableDropRecord_hook = prev_TableDropRecord_hook;
}

4)编译安装插件

[sunbeau@centos7 ~/postgresql-10.1/contrib/droprecord]$ ll
total 8
-rw-rw-r--. 1 sunbiao sunbiao 2887 May 17 10:13 droprecord.c
-rw-rw-r--. 1 sunbiao sunbiao  433 May 17 15:03 Makefile
[sunbeau@centos7 ~/postgresql-10.1/contrib/droprecord]$ make ; make install

初始化数据库修改 postgresql.conf 加载插件

shared_preload_libraries = 'droprecord'         # (change requires restart)

5)启动数据库测试

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Wesley13 Wesley13
2年前
java将前端的json数组字符串转换为列表
记录下在前端通过ajax提交了一个json数组的字符串,在后端如何转换为列表。前端数据转化与请求varcontracts{id:'1',name:'yanggb合同1'},{id:'2',name:'yanggb合同2'},{id:'3',name:'yang
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Java修道之路,问鼎巅峰,我辈代码修仙法力齐天
<center<fontcolor00FF7Fsize5face"黑体"代码尽头谁为峰,一见秃头道成空。</font<center<fontcolor00FF00size5face"黑体"编程修真路破折,一步一劫渡飞升。</font众所周知,编程修真有八大境界:1.Javase练气筑基2.数据库结丹3.web前端元婴4.Jav
Stella981 Stella981
2年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
为什么mysql不推荐使用雪花ID作为主键
作者:毛辰飞背景在mysql中设计表的时候,mysql官方推荐不要使用uuid或者不连续不重复的雪花id(long形且唯一),而是推荐连续自增的主键id,官方的推荐是auto_increment,那么为什么不建议采用uuid,使用uuid究
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这