fmgr按官方的解释就是Postgres函数管理器和函数调用接口,在使用C语言开发PostgreSQL后端应用时,所有与backend交互的函数都必须遵循fmgr.h中定义的一些规范。fmgr.h中定义了很多函数跟宏,如果要学习backend开发,一定要了解这些函数跟宏的用法。
所有可被fmgr直接调用的函数必须有如下签名:
typedefstructFunctionCallInfoBaseData*FunctionCallInfo; typedefDatum (*PGFunction) (FunctionCallInfofcinfo);
什么叫被fmgr调用?还记得之前分析过的pgpool-recovery扩展,用C语言实现了一些用户自定义函数,比如:pgpool_recovery函数,当执行select pgpool_recovery(...)时,Postgres backend就会调用我们用C语言实现的函数,这个函数就是被fmgr调用的函数。pgpool_recovery的函数原型:
Datumpgpool_recovery(PG_FUNCTION_ARGS)
就遵循上面说的函数签名,PG_FUNCTION_ARGS是个宏,展开后就是FunctionCallInfofcinfo。
FmgrInfo结构
typedefstructFmgrInfo{ PGFunctionfn_addr; /* pointer to function or handler to be called */Oidfn_oid; /* OID of function (NOT of handler, if any) */shortfn_nargs; /* number of input args (0..FUNC_MAX_ARGS) */boolfn_strict; /* function is "strict" (NULL in => NULL out) */boolfn_retset; /* function returns a set */unsignedcharfn_stats; /* collect stats if track_functions > this */void*fn_extra; /* extra space for use by handler */MemoryContextfn_mcxt; /* memory context to store fn_extra in */fmNodePtrfn_expr; /* expression parse tree for call, or NULL */} FmgrInfo;
FmgrInfo是最基本的结构,记录了函数的基本信息(system-catalog information),fmgr在调用函数前会先查阅这些信息。
FunctionCallInfoBaseData结构
typedefstructFunctionCallInfoBaseData{ FmgrInfo*flinfo; /* ptr to lookup info used for this call */fmNodePtrcontext; /* pass info about context of call */fmNodePtrresultinfo; /* pass or return extra info about result */Oidfncollation; /* collation for function to use */boolisnull; /* function must set true if result is NULL */shortnargs; /* # arguments actually passed */NullableDatumargs[FLEXIBLE_ARRAY_MEMBER]; } FunctionCallInfoBaseData;
很重要的结构,实际传送到被fmgr调用函数的数据。
InitFunctionCallInfoData宏
填充除args[]数组之外的所有字段:
FunctionCallInvoke宏
调用FunctionCallInfoBaseData结构中定义的函数。
所以被FunctionCallInvoke调用的函数必须有如下签名:
Datumfunction_name(PG_FUNCTION_ARGS) { ... }
常用的几个基础宏
/* fmgr兼容函数标准参数列表 *//** 取得字符集*//** 取得参数个数*//** 参数是否为空*/
获取标准类型数据相关的宏定义
/* these macros hide the pass-by-reference-ness of the datatype: *//* use this if you want the raw, possibly-toasted input datum: *//* use this if you want the input datum de-toasted: *//* and this if you can handle 1-byte-header datums: *//* DatumGetFoo macros for varlena types will typically look like this: *//* And we also offer variants that return an OK-to-write copy *//* Variants which return n bytes starting at pos. m *//* GETARG macros for varlena types will typically look like this: *//* And we also offer variants that return an OK-to-write copy *//* And a b-byte slice from position a -also OK to write */
字符串、varchar相关宏定义
函数返回标准类型相关宏定义
/* these macros hide the pass-by-reference-ness of the datatype: *//* RETURN macros for other pass-by-ref types will typically look like this: */