create aggregate rbitmap_union2 (rbitmap)( sfunc = myfunction, stype = mytype, finalfunc = myfunction_final); 在编写聚合函数时,对每一行都会重复调用指定同一函数,如果要处理的数据是累加的,那么如果不在每次调用之间共享内存空间,而是不停的申
create aggregate rbitmap_union2 (rbitmap)( 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 指向 fmgrinfotypedef 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;
我们只要在 fn_mcxt 这个 memorycontext 下申请内存,就可以让它保持在整个聚合的过程中,申请到的内存块指针,可以存放到 fn_extra 中,也可以作为返回值和入参传递在每次调用间,最后使用 finalfunc 指定的函数进行最终处理。
向指定 memorycontext - fn_mcxt 申请内存的函数如下:
memorycontextalloc(fcinfo->flinfo->fn_mcxt, sizeof(some_type));
它会返回一个指向申请内存空间的 void * 指针。
可以参考 src/backend/utils/adt/arrayfuncs.c 以及下列文章。
参考文章:
http://stackoverflow.com/questions/30515552/can-a-postgres-c-language-function-reference-a-stateful-variable-c-side-possibl