PostgreSQL的hook机制初步学习

本文涉及的产品
云原生数据库 PolarDB MySQL 版,Serverless 5000PCU 100GB
云原生数据库 PolarDB PostgreSQL 版,企业版 4核16GB
推荐场景:
HTAP混合负载
云原生数据库 PolarDB MySQL 版,通用型 2核4GB 50GB
简介:

本文的目的一是为了备忘,二是为了抛砖引玉,希望有更多的人来研究如何使用好PostgreSQL的hook机制。

在研究pg_stat_statments的源代码的时候,发现其中使用了hook机制:例如其中提到了如下几种hook:

复制代码
void                            
_PG_fini(void)                            
{                            
    /* Uninstall hooks. */                        
    shmem_startup_hook = prev_shmem_startup_hook;                        
    ExecutorStart_hook = prev_ExecutorStart;                        
    ExecutorRun_hook = prev_ExecutorRun;                        
    ExecutorFinish_hook = prev_ExecutorFinish;                        
    ExecutorEnd_hook = prev_ExecutorEnd;                        
    ProcessUtility_hook = prev_ProcessUtility;                        
}                            
复制代码

hook机制,是一把双刃剑:

它十分强大,可以让用户有机会切入到PostgreSQL的内部运行机制中,完成用户自定义的控制登录过程、查看系统状态、收集数据库活动的统计信息,甚至控制数据库中特定活动的执行。

当然,一般而言要求hook函数用C语言来编写,如果稍有不慎可能造成数据库系统失常乃至崩溃。

如果按照如下的日文网站的列举,其种类繁多,功能丰富:

http://postgresql.g.hatena.ne.jp/pgsql/20090325

遗憾的是,PostgreSQL的官方文档中没有讲如何使用hook的。只是在release note 中隐约提及。

目前,最权威的资料,来自于:http://wiki.postgresql.org/images/e/e3/Hooks_in_postgresql.pdf

为了进行初步的学习,参考了如下的URL的例子:

http://michael.otacoo.com/postgresql-2/hooks-in-postgres-super-superuser-restrictions/

下面描述建立hook的过程:

此处使用的是 ProcessUtility_hook,作为了例子,当我们从psql等发起 drop database xxx命令的时候。

本hook被激活,然后进行检查,如果被删除的数据库名为 fooddb,那么只有用户foo才有机会删除它。

步骤1:建立contrib目录:

[root@server contrib]# pwd
/soft/postgresql-9.1.2/contrib
[root@server contrib]# mkdir dbrestrict
[root@server contrib]# cd dbrestrict

步骤2:编写程序代码:

需要指出的是,由于我用的是postgresql9.1.2,和上述URL中所用的数据库版本有所不同,故 standard_ProcessUtility 的入口参数有所不同。

复制代码
[root@server dbrestrict]# pwd
/soft/postgresql-9.1.2/contrib/dbrestrict
[root@server dbrestrict]# cat dbrestrict.c
/*
 * dbrestrict.c
 * Restrict drop of a given database to a given super-superuser only.
 * Michael Paquier, 2013
 * Under license "do whatever you want with that"
 */
#include "postgres.h"
#include "miscadmin.h"
#include "tcop/utility.h"

PG_MODULE_MAGIC;

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

static char *undroppabledb = "foodb";
static char *supersuperuser = "foo";

static ProcessUtility_hook_type prev_utility_hook = NULL;

static void dbrestrict_utility(Node *parsetree, const char *queryString, ParamListInfo params,bool isTopLevel, DestReceiver *dest,char *completionTag);

/*
 * Personal process for DB drop restriction
 */
static
void dbrestrict_utility(Node *parsetree,const char *queryString,ParamListInfo params,bool isTopLevel,DestReceiver *dest,char *completionTag)
{
        /* Do our custom process on drop database */
        switch (nodeTag(parsetree))
        {
                case T_DropdbStmt:
                {
                        DropdbStmt *stmt = (DropdbStmt *) parsetree;
                        char *username = GetUserNameFromId(GetUserId());

                        /*
                         * Check that only the authorized superuser foo can
                         * drop the database undroppable_foodb.
                         */
                        if (strcmp(stmt->dbname, undroppabledb) == 0 &&
                                strcmp(username, supersuperuser) != 0)
                                ereport(ERROR,
                                         (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                                           errmsg("Only super-superuser \"%s\" can drop database \"%s\"",
                                                         supersuperuser, undroppabledb)));
                        break;
                }
                default:
                        break;
        }

        /* Fallback to normal process */
        standard_ProcessUtility(parsetree, queryString, params, isTopLevel,dest,completionTag);
}

/*
 * _PG_init
 * Install the hook.
 */
void
_PG_init(void)
{
        prev_utility_hook = ProcessUtility_hook;
        ProcessUtility_hook = dbrestrict_utility;
}

/*
 * _PG_fini
 * Uninstall the hook.
 */
void
_PG_fini(void)
{
        ProcessUtility_hook = prev_utility_hook;
}
[root@server dbrestrict]# 
复制代码

步骤3:建立Makefile:

复制代码
[root@server dbrestrict]# cat Makefile
# contrib/dbrestrict/Makefile

MODULES = dbrestrict
OBJS = dbrestreict.so

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

[root@server dbrestrict]# 
复制代码

步骤4:编译和安装:

复制代码
[root@server dbrestrict]# make
gcc -O2 -Wall -Wmissing-prototypes -Wpointer-arith -Wdeclaration-after-statement -Wendif-labels -Wformat-security -fno-strict-aliasing -fwrapv -fpic -I. -I. -I../../src/include -D_GNU_SOURCE   -c -o dbrestrict.o dbrestrict.c
gcc -O2 -Wall -Wmissing-prototypes -Wpointer-arith -Wdeclaration-after-statement -Wendif-labels -Wformat-security -fno-strict-aliasing -fwrapv -fpic -L../../src/port  -Wl,-rpath,'/usr/local/pgsql/lib',--enable-new-dtags  -shared -o dbrestrict.so dbrestrict.o
rm dbrestrict.o
[root@server dbrestrict]# ls
Makefile  dbrestrict.c  dbrestrict.so
[root@server dbrestrict]# make install
/bin/mkdir -p '/usr/local/pgsql/lib'
/bin/sh ../../config/install-sh -c -m 755  dbrestrict.so '/usr/local/pgsql/lib/'
[root@server dbrestrict]# 
复制代码

步骤5:配置postgresql.conf文件:把编译好的名为dbrestrict的动态库,追加到 shared_preload_libraries中。

[postgres@server data]$ vim postgresql.conf
[postgres@server data]$ cat postgresql.conf | grep 'preload'
shared_preload_libraries = 'dbrestrict'         # (change requires restart)
#local_preload_libraries = ''
[postgres@server data]$ 

这中 shared_preload_libraries 机制还是不错的,事实上EnterpriseDB PPAS的postgresql.conf的此行是这样的:

shared_preload_libraries = '$libdir/dbms_pipe,$libdir/edb_gen'

步骤6:运行验证:

重新启动postgresql

[postgres@server pgsql]$ ./bin/pg_ctl -D ./data start
server starting
[postgres@server pgsql]$ LOG:  loaded library "dbrestrict"
LOG:  database system was shut down at 2013-06-19 21:05:17 CST
LOG:  autovacuum launcher started
LOG:  database system is ready to accept connections

可以看到,对用户 foo 和 goo,他们意图drop database foodb时候,得到的信息是不同的;如果foo是super user,就已经可以删除数据库了:

复制代码
postgres=# create database foodb;
CREATE DATABASE
postgres=# create role foo;
CREATE ROLE
postgres=# \c postgres foo;
FATAL:  role "foo" is not permitted to log in
Previous connection kept
postgres=# drop role foo;
DROP ROLE
postgres=# create role foo login;
CREATE ROLE
postgres=# \c postgres foo;
You are now connected to database "postgres" as user "foo".
postgres=> drop database foodb;
ERROR:  must be owner of database foodb
postgres=> 


postgres=# create role goo login;
CREATE ROLE
postgres=# \c postgres goo;
You are now connected to database "postgres" as user "goo".


postgres=> drop database foodb;
ERROR:  Only super-superuser "foo" can drop database "foodb"
postgres=> 
复制代码

结束!如果有可能,希望更进一步地学习PostgreSQL的各种hook,如果有人可以提供更加详细的信息,十分感谢! 

 

磨砺技术珠矶,践行数据之道,追求卓越价值








本文转自健哥的数据花园博客园博客,原文链接:http://www.cnblogs.com/gaojian/p/3259147.html,如需转载请自行联系原作者


相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
目录
相关文章
|
8月前
|
关系型数据库 数据库 C语言
PostgreSQL服务端开发学习 -- Datum
在使用C语言开发PostgreSQL后端、客户端应用时,Datum无处不在,所以必须要对Datum有很清楚的了解。
289 2
|
9月前
|
关系型数据库 分布式数据库 数据库
沉浸式学习PostgreSQL|PolarDB 19: 体验最流行的开源企业ERP软件 odoo
本文主要教大家怎么用好数据库, 而不是怎么运维管理数据库、怎么开发数据库内核.
1046 2
|
9月前
|
SQL 关系型数据库 测试技术
沉浸式学习PostgreSQL|PolarDB 20: 学习成为数据库大师级别的优化技能
在上一个实验《沉浸式学习PostgreSQL|PolarDB 19: 体验最流行的开源企业ERP软件 odoo》 中, 学习了如何部署odoo和polardb|pg. 由于ODOO是非常复杂的ERP软件, 对于关系数据库的挑战也非常大, 所以通过odoo业务可以更快速提升同学的数据库优化能力, 发现业务对数据库的使用问题(如索引、事务对锁的运用逻辑问题), 数据库的代码缺陷, 参数或环境配置问题, 系统瓶颈等.
878 1
|
8月前
|
关系型数据库 C语言 PostgreSQL
PostgreSQL服务端开发学习 --- 常用结构及宏定义1
本篇主要讲解使用C语言开发PostgreSQL服务端应用(libpq、自定义函数、扩展)常用到的结构及宏定义。
118 0
|
2月前
|
Docker 容器 关系型数据库
【PolarDB-X从入门到精通】 第四讲:PolarDB分布式版安装部署(源码编译部署)
本期课程将于4月11日19:00开始直播,内容包括源码编译基础知识和实践操作,课程目标是使学员掌握源码编译部署技能,为未来发展奠定基础,期待大家在课程中取得丰富的学习成果!
【PolarDB-X从入门到精通】 第四讲:PolarDB分布式版安装部署(源码编译部署)
|
2月前
|
监控 关系型数据库 分布式数据库
【PolarDB开源】PolarDB故障恢复机制:快速恢复与数据一致性保障
【5月更文挑战第22天】阿里云PolarDB的故障恢复机制保证了云数据库的高可用性和一致性。通过ROW快照备份和增量日志,实现秒级备份和恢复,确保数据安全。日志分析快速定位故障,启用备用实例实现快速恢复。分布式事务和强一致性读等技术保障数据一致性。这套全面的解决方案使PolarDB在云原生数据库中表现出色。
494 10
|
2月前
|
关系型数据库 分布式数据库 数据库
【PolarDB开源】PolarDB-X源码解读:分布式事务处理机制揭秘
【5月更文挑战第20天】PolarDB-X,PolarDB家族的一员,专注于大规模分布式事务处理,采用2PC协议保证ACID特性。源码解析揭示其通过预提交、一致性快照隔离和乐观锁优化事务性能,以及利用事务日志进行故障恢复。深入理解其事务处理机制对开发者掌握分布式数据库核心技术至关重要。随着开源社区的发展,更多优化方案将涌现,助力构建更强大的分布式数据库系统。
112 6
|
9天前
|
监控 关系型数据库 分布式数据库
PolarDB故障恢复机制:快速恢复与数据一致性保障
【6月更文挑战第29天】**PolarDB云原生数据库的故障恢复机制确保高可用性与数据一致性。利用ROW快照备份实现秒级备份,结合Redo Log进行时间点恢复。通过日志分析定位故障,快速启动备用实例恢复服务。分布式事务及强一致性读保证数据完整性。PolarDB的高效恢复策略是其在云数据库市场中的关键优势。**
39 16
|
4天前
|
SQL 存储 关系型数据库
关系型数据库PostgreSQL学习
【7月更文挑战第4天】
18 2
|
4天前
|
SQL 存储 关系型数据库
关系型数据库SQL Server学习
【7月更文挑战第4天】
13 2