您的位置:首页 > 娱乐 > 明星 > PostgreSQL内核开发——添加内核函数

PostgreSQL内核开发——添加内核函数

2025/1/6 17:00:35 来源:https://blog.csdn.net/s_lisheng/article/details/139773022  浏览:    关键词:PostgreSQL内核开发——添加内核函数

在PostgreSQL内核的学习过程中,可以尝试向内核中添加一些函数,扩展PostgreSQL的功能。同时可以增加自己对PG内核的理解。这里我们以简单的添加一个helloworld函数为例,分析一下这个过程中涉及到的相关源码。

PostgreSQL添加pg_helloworld函数

这里总结一下如何向PostgreSQL中添加内核函数,以helloworld为例,添加一个内核函数pg_helloworld,显示Hello PostgreSQL!。在添加之前,我们输入select pg_helloworld(),因为PostgreSQL中没有该内核函数,所以显示如下错误:

postgres=# select pg_helloworld();
ERROR:  function pg_helloworld() does not exist
LINE 1: select pg_helloworld();^
HINT:  No function matches the given name and argument types. You might need to add explicit type casts.

这里我们实现这个函数。过程如下:

  1. src/include/catalog/pg_proc.dat中添加如下声明
# add function helloworld()    by chirpyli
{ oid => '9999', descr => 'Hello PostgreSQL',proname => 'pg_helloworld', prorettype => 'text',proargtypes => '', prosrc => 'pg_helloworld' },

其中含义如下:
oid:对象id,唯一不重复
descr:函数描述信息
proname:函数名称
prorettype:返回值类型
proargtypes:参数列表
prosrc:函数名称

  1. src/backend/utils/adt/pseudotypes.c中添加函数pg_helloworld
/*
* pg_helloworld
* function to show 'Hello PostgreSQL!'
*/
Datum
pg_helloworld(PG_FUNCTION_ARGS)
{char str[] = "Hello PostgreSQL!";PG_RETURN_TEXT_P(cstring_to_text(str));
}

这里说明一下参数,能够直接用SQL语句调用的函数(prosrc),他的参数必须是PG_FUNCTION_ARGS,其定义(src/include/fmgr.h)如下:

/* Standard parameter list for fmgr-compatible functions */
#define PG_FUNCTION_ARGS	FunctionCallInfo fcinfo
typedef struct FunctionCallInfoBaseData *FunctionCallInfo;
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 4bool		isnull;			/* function must set true if result is NULL */short		nargs;			/* # arguments actually passed */
#define FIELDNO_FUNCTIONCALLINFODATA_ARGS 6NullableDatum args[FLEXIBLE_ARRAY_MEMBER];
} FunctionCallInfoBaseData;typedef Datum (*PGFunction) (FunctionCallInfo fcinfo);typedef struct FmgrInfo
{PGFunction	fn_addr;		/* pointer to function or handler to be called */Oid			fn_oid;			/* OID of function (NOT of handler, if any) */short		fn_nargs;		/* number of input args (0..FUNC_MAX_ARGS) */bool		fn_strict;		/* function is "strict" (NULL in => NULL out) */bool		fn_retset;		/* function returns a set */unsigned char fn_stats;		/* collect stats if track_functions > this */void	   *fn_extra;		/* extra space for use by handler */MemoryContext fn_mcxt;		/* memory context to store fn_extra in */fmNodePtr	fn_expr;		/* expression parse tree for call, or NULL */
} FmgrInfo;
  1. 验证是否添加成功,重新编译make && make install,初始化数据库initdbpsql连接数据库,select pg_helloworld()查看是否添加成功,结果如下,添加成功。
postgres=# select pg_helloworld();pg_helloworld   
-------------------Hello PostgreSQL!
(1 row)

源码分析

上面成功的添加了pg_helloworld函数后,我们深入思考一下,进行源码分析,看一下其中的细节。数据库处理函数大概的流程是用户发起了调用函数的SQL语句,PG要解析SQL语句,生成语法解析树,首先要识别出是调用系统函数,然后在pg_proc系统表中查询是否有该函数,这个过程是在语义分析阶段做的,最后生成计划树。我们一步一步进行源码分析。具体分析跟踪源码的时候可以用select pg_backend_pid()进行分析。

解析部分

这部分主要是在词法语法分析阶段,识别出是调用函数。关于SQL调用的前期过程以及词法分析过程可参考上一篇PostgreSQL中表名,列名的长度限制,里面有相关的源码分析。这里不再细述。这里只关心解析出函数部分。

解析部分调用主流程如下:

main(int argc, char *argv[])
--> PostmasterMain(argc, argv);--> ServerLoop();--> BackendStartup(port);--> BackendRun(port);--> PostgresMain(ac, av, port->database_name, port->user_name);--> for (;;)        // 在这里不断接收客户端的请求,处理--> exec_simple_query(const char *query_string)     --> pg_parse_query(query_string)

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com