还有一个特殊的API用于提供从C语言函数中返回集合(多行)。

一个返回集合的函数必须遵循版本-1的调用方式。

同样,源代码必须包含funcapi.h,就像上面说的那样。

一个返回集合的函数(SRF)通常为它返回的每个项都调用一次。

因此SRF必须保存足够的状态用于记住它正在做的事情以及在每次调用的时候返回下一个项。

表函数 API 提供了FuncCallContext结构用于帮助控制这个过程。

fcinfo->flinfo->fn_extra

用于保存一个跨越多次调用的指向FuncCallContext的指针。typedef struct

{

/*

* 前面已经被调用的次数

* 初始的时候,call_cntr 被 SRF_FIRSTCALL_INIT() 置为 0,

*并且每次你调用 SRF_RETURN_NEXT() 的时候都递增

*/

uint32 call_cntr;

/*

* 可选的最大调用数量

* 这里的 max_calls 只是为了方便,设置它也是可选的。

* 如果没有设置,你必须提供可选的方法来知道函数何时结束。

*/

uint32 max_calls;

/*

* 指向结果槽位的可选指针

* 这个数据类型已经过时,只用于向下兼容。也就是那些使用已废弃的TupleDescGetSlot()的用户定义 SRF

*/

TupleTableSlot *slot;

/*

* 可选的指向用户提供的杂项环境信息的指针

* user_fctx 用做一个指向你自己的结构的指针,包含任意提供给你的函数的调用间的环境信息

*/

void *user_fctx;

/*

* 可选的指向包含属性类型输入元信息的结构数组的指针

* attinmeta 用于在返回行的时候(也就是说返回复合数据类型)

* 在只返回基本(也就是标量)数据类型的时候并不需要。

* 只有在你准备用 BuildTupleFromCStrings() 创建返回行的时候才需要它。

*/

AttInMetadata *attinmeta;

/*

* 用于必须在多次调用间存活的结构的内存环境

* multi_call_memory_ctx 是由 SRF_FIRSTCALL_INIT() 为你设置的,并且由 SRF_RETURN_DONE() 用于清理。

* 它是用于存放任何需要跨越多次调用 SRF 之间重复使用的内存。

*/

MemoryContext multi_call_memory_ctx;

/*

* 可选的指针,指向包含行描述的结构

* tuple_desc 用于返回行(也就是说复合数据类型)并且只是在你想使用 heap_form_tuple() 而不是 BuildTupleFromCStrings() 制作行的时候需要。

* 请注意这里存储的 TupleDesc 指针通常应该先用 BlessTupleDesc() 处理。

*/

TupleDesc tuple_desc;

} FuncCallContext;

一个SRF使用自动操作FuncCallContext结构

(可以通过fn_extra找到)的若干个函数和宏。使用:SRF_IS_FIRSTCALL()

来判断你的函数是第一次调用还是后继的调用。只有在第一次调用的时候,使用:SRF_FIRSTCALL_INIT()

初始化FuncCallContext。在每次函数调用时(包括第一次),使用:SRF_PERCALL_SETUP()

为使用FuncCallContext做恰当的设置以及清理任何前面的轮回里面剩下的已返回的数据。

如果你的函数有数据要返回,使用:SRF_RETURN_NEXT(funcctx, result)

返回给调用者(result必须是个Datum,要么是单个值,

要么是像前面介绍的那样准备的行)。

最后,如果你的函数结束了数据返回,使用:SRF_RETURN_DONE(funcctx)

清理并结束SRF。

在SRF被调用时的内存环境是一个临时环境,

在调用之间将会被清理掉。

这意味着你不需要pfree所有你palloc的东西;它会自动消失的。

不过,如果你想分配任何跨越调用存在的数据结构,

那你就需要把它们放在其它什么地方。

被multi_call_memory_ctx引用的环境适合用于保存那些需要直到

SRF结束前都存活的数据。在大多数情况下,

这意味着你在第一次调用设置的时候应该切换到multi_call_memory_ctx。

一个完整的伪代码例子看起来像下面这样:Datum

my_set_returning_function(PG_FUNCTION_ARGS)

{

FuncCallContext *funcctx;

Datum result;

更多的声明

if (SRF_IS_FIRSTCALL())

{

MemoryContext oldcontext;

funcctx = SRF_FIRSTCALL_INIT();

oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);

/* 这里放出现一次的设置代码: */

用户代码

if 返回复合

制作 TupleDesc 以及可能还有 AttInMetadata

endif 返回复合

用户定义代码

MemoryContextSwitchTo(oldcontext);

}

/* 每次都执行的设置代码在这里出现: */

用户定义代码

funcctx = SRF_PERCALL_SETUP();

用户定义代码

/* 这里只是用来测试是否完成的一个方法: */

if (funcctx->call_cntr < funcctx->max_calls)

{

/* 这里想返回另外一个条目: */

用户代码

获取结果

SRF_RETURN_NEXT(funcctx, result);

}

else

{

/* 这里完成返回条目的工作了,只需要清理就OK了: */

用户代码

SRF_RETURN_DONE(funcctx);

}

}

一个返回复合类型的完整SRF例子看起来像这样:PG_FUNCTION_INFO_V1(retcomposite);

Datum

retcomposite(PG_FUNCTION_ARGS)

{

FuncCallContext *funcctx;

int call_cntr;

int max_calls;

TupleDesc tupdesc;

AttInMetadata *attinmeta;

/* 只是在第一次调用函数的时候干的事情 */

if (SRF_IS_FIRSTCALL())

{

MemoryContext oldcontext;

/* 创建一个函数环境,用于在调用间保持住 */

funcctx = SRF_FIRSTCALL_INIT();

/* 切换到适合多次函数调用的内存环境 */

oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);

/* 要返回的行总数 */

funcctx->max_calls = PG_GETARG_UINT32(0);

/* 为了结果类型制作一个行描述 */

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")));

/*

* 生成稍后从裸 C 字符串生成行的属性元数据

*/

attinmeta = TupleDescGetAttInMetadata(tupdesc);

funcctx->attinmeta = attinmeta;

MemoryContextSwitchTo(oldcontext);

}

/* 每次函数调用都要做的事情 */

funcctx = SRF_PERCALL_SETUP();

call_cntr = funcctx->call_cntr;

max_calls = funcctx->max_calls;

attinmeta = funcctx->attinmeta;

if (call_cntr < max_calls) /* 在还有需要发送的东西时继续处理 */

{

char **values;

HeapTuple tuple;

Datum result;

/*

* 准备一个数值数组用于版本的返回行

* 它应该是一个C字符串数组,稍后可以被合适的类型输入函数处理。

*/

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));

/* 制作一个行 */

tuple = BuildTupleFromCStrings(attinmeta, values);

/* 把行做成 datum */

result = HeapTupleGetDatum(tuple);

/* 清理(这些实际上并非必要) */

pfree(values[0]);

pfree(values[1]);

pfree(values[2]);

pfree(values);

SRF_RETURN_NEXT(funcctx, result);

}

else /* 在没有数据残留的时候干的事情 */

{

SRF_RETURN_DONE(funcctx);

}

}

在 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函数 postgres_C-语言函数相关推荐

  1. c语言指针自定义函数,c语言函数指针定义,指针函数和函数指针的区别

    往往,我们一提到指针函数和函数指针的时候,就有很多人弄不懂.下面就由小编详细为大家介绍C语言中函数指针,指针函数和函数指针之间的区别. c语言指针函数定义: 函数指针是指向函数的指针变量. 因此&qu ...

  2. vue函数如何调用其他函数?_C语言函数学习-函数的嵌套调用

    文章logo 函数的嵌套调用 C语言中不允许作嵌套的函数定义.因此各函数之间是平行的,不存在上一级函数和下一级函数的问题.但是C语言允许在一个函数的定义中出现对另一个函数的调用.这样就出现了函数的嵌套 ...

  3. r语言 c d生产函数,R语言 函数与模型(12):随机前沿模型SFA

    ______________________________ ______________________________ 查看往期R语言与函数系列 _________________________ ...

  4. c语言goout函数,Go语言函数声明(函数定义)

    函数构成了代码执行的逻辑结构,在Go语言中,函数的基本组成为:关键字 func.函数名.参数列表.返回值.函数体和返回语句,每一个程序都包含很多的函数,函数是基本的代码块. 因为Go语言是编译型语言, ...

  5. c语言程序常用的数学函数,C语言函数——常用数学函数

    C语言的数学函数所在函数库为math.h.stdlio.h.string.h.float.h,使用的时候需要引入.下面是函数及其作用. int abs(int i) 返回整型参数i的绝对值 doubl ...

  6. c语言 时间函数,C语言函数—时间日期函数

    时间日期函数 函数库为time.h.dos.h 在时间日期函数里,主要用到的结构有以下几个: 总时间日期贮存结构tm ┌──────────────────────┐ │struct tm │ │{ ...

  7. r语言的runmed函数_R语言 函数参数的局部匹配验证(match.arg)

    Argument Verification Using Partial Matching Description match.arg matches arg against a table of ca ...

  8. go语言----函数 结构体 接口 多态

    函数 Go语言 函数是反过来声明 变量类型和  函数返回值 一.一个返回值 package main import "fmt"func max(a int,b int) int { ...

  9. C语言 函数指针和指针函数区别 - C语言零基础入门教程

    目录 一.函数指针和指针函数声明的区别 1.函数指针 2.指针函数 二.函数指针和指针函数调用的区别 1.函数指针的调用 2.指针函数的调用 三.猜你喜欢 零基础 Python 学习路线推荐 : C/ ...

  10. C语言-函数、字符串

    函数 C语言函数 传送门 在c语言中,函数是程序的基本单位,每个函数都是具有独立功能的模块.利用函数,可以方便实现程序的模块化,同时使整个程序的组织,编写,阅读,调试,修改和维护更加方便,使程序更清晰 ...

最新文章

  1. Tomcat V6 Examples移植到Apusic V5.1
  2. php 日志处理工具 SeasLog 的使用
  3. java对响应数据做封装_1000种对Java的响应没有死
  4. Spring Boot 最佳实践(四)模板引擎Thymeleaf集成
  5. 深度优先搜索(解题剑指Offer12、13)
  6. node命令错误--nodemon : 无法将“nodemon”项识别
  7. 【转】Linux的僵尸进程解决攻略
  8. 安装Oracle提示OracleMTSRecoveryService 已经存在,解决方法
  9. 2015-数学(3)
  10. 项目开发日报表(第一天)
  11. 某60终端安全管理系统前台SQL注入漏洞复现
  12. Ai 缺失字体解决方法
  13. HTML_水平线详解
  14. MYSQL命令大全自学笔记
  15. 制造型企业如何上云?
  16. 微信小程序组件、web-view、h5之间交互
  17. AI基础课正式进入高中教材,新课标改革2018秋季执行!
  18. 《通用数据保护条例》(GDPR)系列解读四:出海欧洲必须遵守的七大数据处理原则
  19. [Oracle]-[recyclebin][索引]-回收站恢复的索引名称修改
  20. 【Java面试题】List如何一边遍历,一边删除?

热门文章

  1. SIMXXX 在高德地图定位到我的位置
  2. 论文笔记:联邦学习——Federated Learning: Strategies for Improving Communication Efficiency
  3. 据为己有!这位985博导把审稿的文章拒了,自己投!
  4. jQuery - end方法的用法
  5. python学习手册教程_python学习手册:如何学习python学习教程?
  6. 【数据库】Navicat编写MySQL自定义函数详解
  7. VNode 是什么? 什么是虚拟 DOM?
  8. 网络营销都有什么特点
  9. J2EE疑难解决实例--转自JSP中文网
  10. jsp对象的四大作用域的简单介绍