1.FuncCallContext详细说明
/*-------------------------------------------------------------------------
* 函数调用上下文struct(SRF为Set Returning Functions)
*-------------------------------------------------------------------------
*
* 此结构保存设置返回函数的函数上下文。
* 使用fn_extra在调用之前保存一个指针
* 此struct适用于函数需要返回多行时使用
*/
typedef struct FuncCallContext
{
/*
* 函数以前调用过的次数
* call_cntr由SRF_FIRSTCALL_INIT()初始化为0
* 并在每次调用SRF_RETURN_NEXT()时递增
*/
uint64 call_cntr;
/*
* [可选参数]最大调用数量
* max_calls只是为了方便起见设置它是可选的.如果没有设置
* 你必须提供替代方法来知道什么时候函数已经完成
* 这个值类似select中的limit
*/
uint64 max_calls;
/*
* 可选指针到插槽(已过时,不要再使用)
* 已过时,只是为了兼容以前的版本
*/
TupleTableSlot *slot;
/*
* [可选参数]用户提供的上下文指针
* uuser_fctx用作指向您自己定义的指针
* 以便在函数调用之间保留任意上下文信息
*/
void *user_fctx;
/*
* [可选参数]指向包含属性类型输入元数据的struct的指针
* attinmeta用于返回元组(即复合数据类型)
* 并且在返回基本数据类型时不使用
* 仅当您打算使用BuildTupleFromCStrings()创建返回元组时才需要
*/
AttInMetadata *attinmeta;
/*
* 使用多次调用必须的structures内存上下文
* multi_call_memory_ctx在调用SRF_FIRSTCALL_INIT()时设置
* 并由SRF_RETURN_DONE()用于清理.
* 对于要在SRF中多次调用中重用的内存来说这是最合适的内存上下文.
*/
MemoryContext multi_call_memory_ctx;
/*
* [可选参数]指向包含元组描述的struct的指针
* tuple_desc在返回元组(即复合数据类型)时使用
* 只有在要使用heap_form_tuple()而不是BuildTupleFromCStrings()构建元组时才需要使用
* 请注意,TupleDesc指针应该先运行BlessTupleDesc()
*/
TupleDesc tuple_desc;
} FuncCallContext;
2.AttInMetadata示例,windows或Linux均可,如果不能编译,请添加必须的头文件
#include "postgres.h"
#include "fmgr.h"
#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif
PGDLLEXPORT Datum retcomposite(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(retcomposite);
Datum retcomposite(PG_FUNCTION_ARGS) {
FuncCallContext *funcctx;
uint64 call_cntr, max_calls;
TupleDesc tupdesc;
AttInMetadata *attinmeta;
/* stuff done only on the first call of the function */
if (SRF_IS_FIRSTCALL()) {
MemoryContext oldcontext;
/* create a function context for cross-call persistence*/
funcctx = SRF_FIRSTCALL_INIT();
/* switch to memory context appropriate for multiple function calls */
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
/*设置返回的记录集数量 */
funcctx->max_calls = PG_GETARG_UINT32(0);
/* Build a tuple descriptor for our result type */
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("function returning record called in context that cannot accept type record")));
/* generate attribute metadata needed later to produce tuples from raw C strings */
attinmeta = TupleDescGetAttInMetadata(tupdesc);
funcctx->attinmeta = attinmeta;
MemoryContextSwitchTo(oldcontext);
//elog(NOTICE, "%d", 0);
}
//elog(NOTICE, "%s", "x");
/* stuff done on every call of the function */
funcctx = SRF_PERCALL_SETUP();
call_cntr = funcctx->call_cntr;
max_calls = funcctx->max_calls;
attinmeta = funcctx->attinmeta;
if (call_cntr < max_calls) { /* do when there is more left to send */
char **values;
HeapTuple tuple;
Datum result;
/* Prepare a values array for building the returned
tuple. This should be an array of C strings which
will be processed later by the type input functions. */
values = (char **)palloc(3 * sizeof(char *));
values[0] = (char *)palloc(16 * sizeof(char));
values[1] = (char *)palloc(16 * sizeof(char));
values[2] = (char *)palloc(16 * sizeof(char));
snprintf(values[0], 16, "%d", 1 * PG_GETARG_INT32(1));
snprintf(values[1], 16, "%d", 2 * PG_GETARG_INT32(1));
snprintf(values[2], 16, "%d", 3 * PG_GETARG_INT32(1));
/* build a tuple */
tuple = BuildTupleFromCStrings(attinmeta, values);
/* make the tuple into a datum */
result = HeapTupleGetDatum(tuple);
/* clean up (this is not really necessary) */
pfree(values[0]);
pfree(values[1]);
pfree(values[2]);
pfree(values);
SRF_RETURN_NEXT(funcctx, result);
} else { /* do when there is no more left */
SRF_RETURN_DONE(funcctx);
}
}
3.函数定义
其中retcomposite的第1个参数是调用次数(返回的记录数量)
create type __retcomposite as (f1 integer, f2 integer, f3 integer);
create function retcomposite(integer, integer)
returns setof __retcomposite
as 'pg_kmcb', 'retcomposite'
language C immutable strict;
或者使用out参数
create function retcomposite(in integer, in integer,out f1 integer, out f2 integer, out f3 integer)
returns setof record
as 'pg_kmcb', 'retcomposite'
language C immutable strict;
注意:函数定义只能使用其中的一个
4.定义control,这里我编译的扩展是pg_kmcb.so或pg_kmcb.dll
comment = '自定义C风格的函数'
default_version = '1.0'
module_pathname = '$libdir/pg_kmcb'
relocatable = true
5.创建扩展
以postgres用户连接到指定的数据库,然后运行
create extension pg_kmcb;
6.使用方法
返回100条一样的记录
select * from retcomposite(100,1);