代码版本: 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
4.进入src/interfaces/libpq 编译文件
在编译链接src/backend/下的postgres程序时,libpq库文件还没有编译会报错,所以需要先进行本步骤先编译
cd src/interfaces/libpq
make
5.编译安装数据库
返回源代码根目录编译安装
make ; make install
6.测试
二、使用插件
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)启动数据库测试
略