CREATE AGGREGATE union(bitmap)
(
sfunc = myfunction,
stype = mytype,
FINALFUNC = myfunction_final
);
在编写聚合函数时,对每一行都会重复调用指定同一函数,如果要处理的数据是累加的,那么如果不在每次调用之间共享内存空间,而是不停的申请释放新的内存,那么速度会变得很慢,所以在这时共享内存是十分有用的:
PostgreSQL 有 MemoryContext 的概念,如果普通的使用 palloc 申请内存空间,系统会向 CurrentMemoryContext 申请,而据我试验猜测,聚合函数在每次调用时,都会切换 CurrentMemoryContext,所以普通的 palloc 是不能使用的。
在使用 Version 1 Calling Conventions 时,有如下宏定义, PG_FUNCTION_ARGS 是我们编写函数的实际入参:
#define PG_FUNCTION_ARGS FunctionCallInfo fcinfo
FunctionCallInfo 是指向 FunctionCallInfoData 结构的指针:
/*
* This struct is the data actually passed to an fmgr-called function.
*/
typedef struct FunctionCallInfoData
{
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 */
bool isnull; /* function must set true if result is NULL */
short nargs; /* # arguments actually passed */
Datum arg[FUNC_MAX_ARGS]; /* Arguments passed to function */
bool argnull[FUNC_MAX_ARGS]; /* T if arg[i] is actually NULL */
} FunctionCallInfoData;
其中的 flinfo 指向 FmgrInfo
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 */
<span style="color:#ff0000;">void *fn_extra</span>; /* extra space for use by handler */
<span style="color:#ff0000;">MemoryContext fn_mcxt</span>; /* memory context to store fn_extra in */
fmNodePtr fn_expr; /* expression parse tree for call, or NULL */
} FmgrInfo;
我们只要在 fn_mcxt 这个 MemoryContext 下申请内存,就可以让它保持在整个聚合的过程中,申请到的内存块指针,可以存放到 fn_extra 中,也可以作为返回值和入参传递在每次调用间,最后使用 FINALFUNC 指定的函数进行最终处理。
向指定 MemoryContext - fn_mcxt 申请内存的函数如下:
MemoryContextAlloc(fcinfo->flinfo->fn_mcxt, sizeof(some_type));
它会返回一个指向申请内存空间的 void * 指针。
可以参考 src/backend/utils/adt/arrayfuncs.c 以及下列文章。
参考文章: