在 SQL 里声明这个函数的一个方法是:
CREATE TYPE __retcomposite AS (f1 integer, f2 integer, f3 integer);
CREATE OR REPLACE FUNCTION retcomposite(integer, integer)
RETURNS SETOF __retcomposite
AS 'filename', 'retcomposite'
LANGUAGE C IMMUTABLE STRICT;
另外一个方法是使用 OUT 参数:
CREATE OR REPLACE FUNCTION retcomposite(IN integer, IN integer,
OUT f1 integer, OUT f2 integer, OUT f3 integer)
RETURNS SETOF record
AS 'filename', 'retcomposite'
LANGUAGE C IMMUTABLE STRICT;
请注意在这个方法里,函数的输出类型实际上是匿名的 record 类型。
参阅源码发布包里的 contrib/tablefunc 获取更多有关返回集合的函数的例子。
多态参数和返回类型
C 语言函数可以声明为接受和返回多态的类型 anyelement,anyarray,anynonarray 和 anyenum。参阅 Section 34.2.5 获取有关多态函数的更详细的解释。如果函数参数或者返回类型定义为多态类型,那么函数的作者就无法预先知道他将收到的参数,以及需要返回的数据。在 fmgr.h 里有两个过程,可以让版本-1的 C 函数知道它的参数的确切数据类型以及它需要返回的数据类型。这两个过程叫 get_fn_expr_rettype(FmgrInfo *flinfo) 和 get_fn_expr_argtype(FmgrInfo *flinfo, int argnum)。它们返回结果或者参数的类型 OID,如果这些信息不可获取,则返回 InvalidOid。结构 flinfo 通常是以 fcinfo->flinfo 进行访问的。参数 argnum 是以 0 为基的。get_call_result_type 也可以用做 get_fn_expr_rettype 替换。
比如,假设我们想写一个函数接受任意类型的一个元素,并且返回该类型的一个一维数组:
PG_FUNCTION_INFO_V1(make_array);
Datum
make_array(PG_FUNCTION_ARGS)
{
ArrayType *result;
Oid element_type = get_fn_expr_argtype(fcinfo->flinfo, 0);
Datum element;
int16 typlen;
bool typbyval;
char typalign;
int ndims;
int dims[MAXDIM];
int lbs[MAXDIM];
if (!OidIsValid(element_type))
elog(ERROR, "could not determine data type of input");
/* 获取提供的元素 */
element = PG_GETARG_DATUM(0);
/* 我们的维数是 1 */
ndims = 1;
/* 有一个元素 */
dims[0] = 1;
/* 数组下界是 1*/
lbs[0] = 1;
/* 获取有关元素类型需要的信息 */
get_typlenbyvalalign(element_type, &typlen, &typbyval, &typalign);
/* 然后制作数组 */
result = construct_md_array(&element, ndims, dims, lbs,
element_type, typlen, typbyval, typalign);
PG_RETURN_ARRAYTYPE_P(result);
}
下面的命令用 SQL 声明函数 make_array:
CREATE FUNCTION make_array(anyelement) RETURNS anyarray
AS 'DIRECTORY/funcs', 'make_array'
LANGUAGE C STRICT;
请注意使用 STRICT;这一点非常重要,因为代码没有认真测试空输入。
共享内存和 LWLocks
附加模块可以在服务器启动的时候保留 LWLocks 和分配一篇共享内存。附加模块的共享库必须通过在 shared_preload_libraries 里面声明来预装载。共享内存是通过在你的 _PG_init 函数里面调用:
void RequestAddinShmemSpace(int size)
来保留的。
LWLocks 是通过在 _PG_init 里调用:
void RequestAddinLWLocks(int n)
来保留的。
为了避免可能的冲突条件,在访问每个后端并且初始化其分配的共享内存的时候,每个后端都应该使用 LWLock AddinShmemInitLock,如下所示:
static mystruct *ptr = NULL;
if (!ptr)
{
bool found;
LWLockAcquire(AddinShmemInitLock, LW_EXCLUSIVE);
ptr = ShmemInitStruct("my struct name", size, &found);
if (!ptr)
elog(ERROR, "out of shared memory");
if (!found)
{
初始化 shmem 区域的内容
使用下面一行请求任何需要的 LWLocks:
ptr->mylockid = LWLockAssign();
}
LWLockRelease(AddinShmemInitLock);
}
