第 11 课 PostgreSQL 增加一个内核C函数

第一步 实现函数

增加的函数都放在src/backend/utils目录下,我要实现的函数是从服务器查询,并返回给调用者。
C函数原型:

char * sys_test(const uint32 id, const uint32 age)

开发者需要根据自己的需要,选择目录和文件:


image.png

我需要实现的功能在现有的文件中不存在相关性,我在adt目录下自己创建了一个文件:test.c,文件内容如下:

#include "postgres.h"

#include <sys/file.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>

#include "access/heapam.h"
#include "catalog/pg_type.h"
#include "funcapi.h"
#include "miscadmin.h"
#include "postmaster/syslogger.h"
#include "storage/fd.h"
#include "utils/builtins.h"

/*
 * Read a page, returning it as binary
 */
Datum
sys_test(PG_FUNCTION_ARGS)
{
    uint32      id = PG_GETARG_INT32(0);
        uint32      age = PG_GETARG_INT32(1);

    printf("111111111111111111111\n");
    strcpy(buf, "xxxxxxxxxxxxxxxxxx");
    SET_VARSIZE(buf, nbytes + VARHDRSZ);

    PG_RETURN_TEXT_P(buf);
}

实际功能还需要实现,我就打个样。
修改Makefile,使其可以被编译。打开文件adt/Makefile,增加文件test

如果你实现的函数,在现有的文件中实现,就不需要修改Makefile。

第二步 支持外部访问

打开文件:src/include/utils/builtins.h,在文件尾部增加自己的函数。
extern Datum sys_test(PG_FUNCTION_ARGS);

第三步 注册到名字空间

打开:src/include/catalog/pg_proc.h,找一个合适的位置增加自己的函数定义:

DATA(insert OID = 13624 ( sys_test      PGNSP 0 PGUID 12 t f f f t f v 2 17 17 i f i f f "23 23" _null_  _null_ _null_ _null_ _null_ _null_ sys_read_page 2D _null_ ));
DESCR("sys_test");

其中的OID,不可重复,自己YY。

在模板库中插入记录,使任何库一创建就有。对于系统表来说,在它的头文件里有对这个系统表的详细定义说明,在这个头文件下面能按格式预置一些记录,这些记录在initdb时会插入到模板库的对应系统表中。具体来说,这些预置的记录,在编译过程中,会被perl脚本转换到postgres.bki中,这个bki文件在安装目录的share文件夹,当initdb时,会加载这个bki并解析成一条条sql运行,创建出一个个系统表,插入初始记录,把初始的信息准备好。有兴趣者可以看看initdb模块中 bootstrap_template1函数,初始化模块时第1件事就是加载postgres.bki文件翻译解析执行。

第四步 编译和验证函数可用

重新编译代码,使其修改重新编译。

make && make install

这种函数如果修改了pg_proc.h就必须要重新初始化数据库,不然不会生效:

./initdb ../data

在bin目录下启动服务进程:

./postgres

使用isql连接服务器:

./psql postgres

查询函数定义:

postgres-# \df+ SYS_TEST
                                                        功能列表
   Schema    |     Name      | Result data type | Argument data types  | Owner  | Language |  Source code  | Description 
-------------+---------------+------------------+----------------------+--------+----------+---------------+-------------
 SYS_CATALOG | SYS_TEST | BYTEA            | TEXT, BIGINT, BIGINT | SYSTEM | INTERNAL | sys_test | 

我们仔细看,函数参数“TEXT, BIGINT, BIGINT”,其实是错误的,与我们的函数定义:

char * sys_test(const uint32 id, const uint32 age)

是不一样的,参数列表错误,下面我们要找到原因,并修改。
关于参数设置可以参考:https://blog.csdn.net/postgres20/article/details/53446231

在pg_proc.h中插入的记录是什么含义?

以第一行为例详细说明如下:
DATA(insert OID = 13624 ( sys_read_page PGNSP 0 PGUID 12 t f f f t f v 2 17 17 i f i f f "25 20 20" null null null null null null sys_read_page 2D null ));

13624–OID使用内核中未使用的OID即可(src/include/catalog下unused_oids,可以显示未使用的oid) postgres内部预留了1W多个oid给系统用,选一个没有的就行,如果不知道哪些可用,在\src\include\catalog\ 下有个脚本文件unused_oids,运行一下就能找出哪些oid可用,但要这是一个linux脚本,需要在linux下运行。

PGNSP–函数所属的名字空间的OID,PGNSP即pg_catalog(oid=11),内置函数添加此值固定

PGUID–函数的拥有者OID,PGUID及initdb时指定用户(oid=10),内置函数添加此值固定

12–实现语言或该函数的调用接口,内置函数使用12(internal),SQL用14

t–函数是否为一个聚集函数
f–函数是否为一个窗口函数
f–函数是一个安全性定义者(即,一个”setuid”函数)
f–该函数没有副作用。除了通过返回值,没有关于参数的信息被传播。任何会抛出基于其参数值的错误信息的函数都不是泄露验证的。
t–当任意调用函数为空时,函数是否会返回空值。在那种情况下函数实际上根本不会被调用。非”strict”函数必须准备好处理空值输入。
f–函数是否返回一个集合(即,指定数据类型的多个值)
v–未知

2–输入参数的个数,对应后面的""25 20 20""两个参数,明显我们这里写错了,找到了原因,我们修改为我们对应的参数个数和类型:

"25 20 20" 改为 “23 23”,
23表示int4,继续往下看,有说明。

17–具有默认值的参数个数
17–返回值的数据类型

“25 20 20”–函数参数的数据类型的数组,这只包括输入参数(含INOUT和VARIADIC参数),因此也表现了函数的调用特征 重载函数也凭这区别,如果有多个,参数肯定不同,这个不同即可以是数量不同,也可以是类型不同,25 20 20 就是代表类型,如下:

TEST=# select oid,typname from pg_type where oid in (1082,23,1114,1184,17,25);
 OID  |   TYPNAME   
------+-------------
   17 | BYTEA
   23 | INT4
   25 | TEXT
 1082 | DATE
 1114 | TIMESTAMP
 1184 | TIMESTAMPTZ

null–函数参数的数据类型的数组,这包括所有参数(含OUT和INOUT参数)。但是,如果所有参数都是IN参数,这个域将为空。注意下标是从1开始 ,然而由于历史原因proargtypes的下标是从0开始

null–函数参数的模式的数组。编码为: i表示IN参数 , o表示OUT参数, b表示INOUT参数, v表示VARIADIC参数, t表示TABLE参数。 如果所有的参数都是IN参数,这个域为空。注意这里的下标对应着proallargtypes而不是proargtypes中的位置

null–函数参数的名字的数组。没有名字的参数在数组中设置为空字符串。如果没有一个参数有名字,这个域为空。注意这里的下标对应着proallargtypes而不是proargtypes中的位置

null–默认值的表达式树(按照nodeToString()的表现方式)。这是一个pronargdefaults元素的列表,对应于最后N个input参数(即最后N个proargtypes位置)。如果没有一个参数具有默认值,这个域为空

null–数据类型OID为了应用转换

我们再次来看看,是不是都对了

postgres=# \df sys_test
                               功能列表
   Schema    |     Name      | Result data type | Argument data types 
-------------+---------------+------------------+---------------------
 SYS_CATALOG | SYS_TEST | BYTEA            | INTEGER, INTEGER

第五步 调用函数

postgres=# select SYS_TEST(1,2);

其他可用输出参数:

信息报告
  \d [NAME]      描述表, 索引, 序列, 或者视图
  \d{t|i|s|v|S} [PATTERN] (附加 "+" 获取更多信息)
                 列出表/索引/序列/视图/系统表
  \da [PATTERN]  列出聚集函数
  \db [PATTERN]  列出表空间(附加 "+" 获取更多信息)
  \dc [PATTERN]  列出编码转换
  \dC            列出定义的转换
  \dd [PATTERN]  列出对象的注释
  \dD [PATTERN]  列出域
  \df [PATTERN]  列出函数(附加 "+" 获得更多信息)
 \dF [PATTERN]  列出全文搜索配置(附加 "+" 获得更多信息)
  \dFd [PATTERN] 列出全文搜索词典(附加 "+" 获得更多信息)
  \dFt [PATTERN] 列出全文搜索模板
 \dFp [PATTERN] 列出全文搜索分析器(附加 "+" 获得更多信息)
  \dm[S+] [PATTERN]      list materialized views
  \dn [PATTERN]  列出模式(附加 "+" 获得更多信息)
  \do [NAME]     列出操作符
  \dp [PATTERN]  列出表, 视图, 及序列的访问权限
  \dP [PATTERN]  列出包(附加 "+" 获得更多信息)
 \dr [PATTERN]  列出角色
  \dT [PATTERN]  列出数据类型(附加 "+" 获得更多信息)
  \du [PATTERN]  列出用户

  \l             列出所有数据库(附加 "+" 获得更多信息)
  \ll [PATTERN]  列出锁
  \llc           列出锁总数
  \lx            列出xid最大值
  \lredolog      列出当前的重做日志

  \lc [PATTERN]          列出所有连接
  \lac [PATTERN]         列出活动连接
  \lfc [PATTERN]         列出空闲连接
  \lwc [PATTERN]         列出等待连接
  \lmc                   列出最大连接数

  \lstatdb [PATTERN]     列出数据库统计信息
  \lstatidx [PATTERN]    列出索引统计信息
  \lstatseq [PATTERN]    列出序列统计信息
  \lstattable [PATTERN]  列出表格统计信息

发现更多宝藏

我在喜马拉雅上分享声音

《PostgreSQL数据库内核分析》,点开链接可以听听,有点意思。

《数据库系统概论(第4版)》,点开链接可以听听,有点意思。

更多IT有声课程,点我发现更多

第 0 课 PostgreSQL 系列文章列表

其他相关文章分享列表:

第 23 课 PostgreSQL 创建自己的数据库、模式、用户
第 22 课 PostgreSQL 控制文件
第 21 课 PostgreSQL 日志系统
第 16 课 查询过程源码分析
第 15 课 PostgreSQL 系统参数配置
第 14 课 PostgreSQL 数据存储结构
第 13 课 PostgreSQL 存储之Page(页面)源码分析
第 12 课 PostgreSQL 认证方式
第 11 课 PostgreSQL 增加一个内核C函数
第 10 课 PostgreSQL 在内核增加一个配置参数
第 09 课 PostgreSQL 4种进程启动方式
第 08 课 PostgreSQL 事务介绍
第 07 课 PostgreSQL 数据库、模式、表、空间、用户间的关系
第 06 课 PostgreSQL 系统表介绍
第 05 课 PostgreSQL 编译源代码进行开发
第 04 课 PostgreSQL 安装最新的版本
第 03 课 PostgreSQL 代码结构
第 02 课 PostgreSQL 的特性、应用、安装
第 01 课 PostgreSQL 简介及发展历程

上面文章都在专辑中:PostgreSQL专辑链接,点我查看

如果有用,可以收藏这篇文件,随时在更新....

更多交流加群: PostgreSQL内核开发群 876673220

亲,记得点赞、留言、打赏额!!!

上一课
下一课

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,219评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,363评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,933评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,020评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,400评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,640评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,896评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,597评论 0 199
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,327评论 1 244
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,581评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,072评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,399评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,054评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,083评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,849评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,672评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,585评论 2 270