PostgreSQL C风格的自定义函数FuncCallContext结构体描述及示例

来源:互联网 发布:莆田精仿鞋淘宝网店 编辑:程序博客网 时间:2024/06/17 20:05

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_MAGICPG_MODULE_MAGIC;#endifPGDLLEXPORT 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 __retcompositeas '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 recordas '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);
阅读全文
0 0
原创粉丝点击