摘要
这期主要是想填个坑,在上期中留下了一个
pg_reload_conf()处理流程
,找到代码看了一下,发现这块只有寥寥几行,该函数就是向postmaster进程发了一个SIGHUP
信号,后续流程就是上期中的信号“1”处理流程,但pg_reload_conf()
是一个内建函数,那么内建函数的调用过程涉及sql的接收、解析、执行等等,这个包含了sql引擎的一部分流程,是比较核心的内容,现阶段我还没这个能力去把这部分讲清楚,所以先从简单的开始,先介绍如何写一个内建函数,通过一个内建函数例子来学习和梳理内建函数的实现过程,同时也填上上期挖的坑。
先填坑
pg_reload_conf()
函数位于postgres/src/backend/storage/ipc/signalfuncs.c
文件中,实际上就是通过kill()向postmaster进程发送SIGHUP
信号,而后续postmaster进程收到SIGGUP
信号后的流程参见“postgresql 15源码浅析(3)—— 信号"1"的使命“。
/*
* Signal to reload the database configuration
*
* Permission checking for this function is managed through the normal
* GRANT system.
*/
Datum
pg_reload_conf(PG_FUNCTION_ARGS)
{
if (kill(PostmasterPid, SIGHUP))
{
ereport(WARNING,(errmsg("failed to send signal to postmaster: %m")));
PG_RETURN_BOOL(false);
}
PG_RETURN_BOOL(true);
}
复制
内建(builtin)函数
内建函数就是postgres的内置函数,可以通过select方式调用,在第一期中介绍初始化的时候提到过,这些函数在初始化的时候被创建,通过执行postgres.bki中的后端接口将函数插入到pg_proc表中,而这些内建函数是在postgres/src/backend/utils/fmgrtab.c
中注册在fmgr_builtins[]数组里。
/*
* This table stores info about all the built-in functions (ie, functions
* that are compiled into the Postgres executable).
*/
typedef struct
{
Oid foid; /* OID of the function */
short nargs; /* 0..FUNC_MAX_ARGS, or -1 if variable count */
bool strict; /* T if function is "strict" */
bool retset; /* T if function returns a set */
const char *funcName; /* C name of the function */
PGFunction func; /* pointer to compiled function */
} FmgrBuiltin;
复制
函数指针的定义如下:
typedef Datum (*PGFunction) (FunctionCallInfo fcinfo);
复制
- 返回值 Datum :在32位系统中为 unsigned int型,在64位系统中位 unsigned long int,可以表示一个值或者一个指针。
- 参数 PG_FUNCTION_ARGS:FunctionCallInfoBaseData
typedef struct FunctionCallInfoBaseData
{
FmgrInfo *flinfo; /* ptr to lookup info used for this call */
fmNodePtr context; /* pass info about context of call */
fmNodePtr resultinfo; /* pass or return extra info about result */
Oid fncollation; /* collation for function to use */
#define FIELDNO_FUNCTIONCALLINFODATA_ISNULL 4
bool isnull; /* function must set true if result is NULL */
short nargs; /* # arguments actually passed */
#define FIELDNO_FUNCTIONCALLINFODATA_ARGS 6
NullableDatum args[FLEXIBLE_ARRAY_MEMBER];
} FunctionCallInfoBaseData;
复制
typedef struct NullableDatum
{
#define FIELDNO_NULLABLE_DATUM_DATUM 0
Datum value;
#define FIELDNO_NULLABLE_DATUM_ISNULL 1
bool isnull;
/* due to alignment padding this could be used for flags for free */
} NullableDatum;
复制
参数列表保存在args[]中。
Hello PostgreSQL 15
实现函数功能
实现一个Hello()函数,功能非常简单,就是输出“Hello PostgreSQL 15”的字符串。
/*-------------------------------------------------------------------------
*
* hello.c
* Returns the Hello PostgreSQL 15 string
*
* Copyright (c) 1998-2022, PostgreSQL Global Development Group
*
* IDENTIFICATION
*
* src/backend/utils/adt/hello.c
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "utils/builtins.h"
Datum
hello(PG_FUNCTION_ARGS)
{
PG_RETURN_TEXT_P(cstring_to_text("Hello PostgresSQL 15."));
}
复制
理论上可以把这个文件放在任何位置,为了“优雅”一点,我们把它放在src/backend/utils/adt/hello.c
下面。
注意:需要包含两个头文件postgres.h和utils/builtins.h
修改Makefile
在OBJS中添加我们新建的hello目标文件。
注册hello函数
在postgres/src/include/catalog/pg_proc.dat
中注册hello()
函数。
实际上pg_proc.dat是配置文件,通过postgres/src/backend/utils/Gen_fmgrtab.pl
读取改文件,生成fmgrprotos.h和fmgrtab.c。
同时,postgres/src/backend/genbki.pl会生产postgres.bki文件。
文件内容如下:
- fmgrprotos.h
- fmgrtab.c
- postgres.bki
验证
编译安装
#!/bin/bash
rm -rf /home/frank/pgsql
#./configure --prefix=/home/frank/pgsql --enable-debug
./configure --prefix=/usr/local/pgsql --enable-debug
make -j 7
sudo make install
make clean
复制
运行验证
总结
为PostgreSQL 15添加一个内建函数还是相对比较简单的,总结下来一共三步:1.添加函数功能(按照规范实现一个具体功能的.c代码;2.修改Makefile文件,添加新增的OBJS;3.修改pg_proc.dat配置文件,注册内建函数;
其实与写内建函数类似的做法还要两种,一是C FUNCTION;二是contrib下增加插件;这三种方法实现函数的格式基本一直,但注册方法略有不同。
今天填了一个坑。之前也写过C FUNCTION和插件实现方法,但是对这两种函数的调用流程还不是很清楚,后续把这个坑补上。
备注
待填的坑 | 挖坑时间 | 填坑帖子 | 填坑时间 |
---|---|---|---|
理解bki | 2022-05-22 | ||
实现自定义命令的psql | 2022-05-24 | ||
pg_reload_conf()处理流程 | 2022-05-29 | Hello PostgreSQL 15 | 2022-06-04 |
插件是如何加载的 | 2022-06-04 |