有时我们需要定义返回结果集的函数,本文演示如何编码。

遂古之初,谁传道之?上下未形,何由考之?《天问》

1、函数定义

C语言定义部分

PG_FUNCTION_INFO_V1(quanzl_dummy_setof);Datumquanzl_dummy_setof(PG_FUNCTION_ARGS){...}

这里与一般的SQL函数的C语言定义没什么区别,目前调用协议也只有V1。

SQL定义,如果希望返回三个字段的值:

CREATE FUNCTION quanzl_dummy_setof(OUT int, OUT int, OUT int)AS 'quanzl_dummy' LANGUAGE C;

可以指定出参名,不指定它们自动生成为:column1、column2、column3。

2、函数调用上下文FuncCallContext

src/include/funcapi.h,这里也定义了结果集函数需要的其他宏。

uint64    call_cntr;uint64    max_calls;void     *user_fctx;

call_cntr:已调用次数,不包含本次,由PG函数调用系统自动维护。

max_calls:最大调用次数,但PG不会以它为依据结束函数的调用,它是给用户代码使用的,至少目前是这样。

user_fctx:可用于在调用间传递用户自定义数据,PG对它不做任何处理。

3、结果集函数的开始

FuncCallContext *funcctx;char ***values;if (SRF_IS_FIRSTCALL()){   TupleDesctupdesc;   funcctx = SRF_FIRSTCALL_INIT();   oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);   tupdesc = CreateTemplateTupleDesc(2);   TupleDescInitEntry(tupdesc, (AttrNumber) 1, "col1",               INT4OID, -1, 0);   TupleDescInitEntry(tupdesc, (AttrNumber) 2, "col2",               INT4OID, -1, 0);   TupleDescInitEntry(tupdesc, (AttrNumber) 3, "col3",               INT4OID, -1, 0);   funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);  ... 生成 values 的数据 ...   funcctx->user_fctx = values;   funcctx->max_calls = length of values;   MemoryContextSwitchTo(oldcontext);}

多次调用内存上下文在SRF_FIRSTCALL_INIT之后才有效,这里顺序不能错。切换上下文不是必须的,一般我们会这么做,将函数专用的数据生成在这里,即使忘记回收调用结束后会自动清理。

TupleDesc的定义必须与SQL定义匹配,轻则结果错误,重则直接崩溃。

funcctx->attinmeta 照葫芦画瓢即可,没什么特别,后边生成元祖时会用得到。

values的生成根据业务需要编写,演示用可以写死一个固定数组。

4、单次调用与函数结束

funcctx = SRF_PERCALL_SETUP();values = (char ***) funcctx->user_fctx;if (funcctx->call_cntr < funcctx->max_calls){   ... 返回单条结果 ...}else   SRF_RETURN_DONE(funcctx);

第一个看名字也知道,是每次必须调用的。

第一次调用时生成的user_fctx,在后续调用中取出来继续利用。

在没有结束之前,每次调用只返回一条记录;当调用次数达到上限时,结束调用。

5、返回单条结果

tuple = BuildTupleFromCStrings(funcctx->attinmeta, values[funcctx->call_cntr]);result = HeapTupleGetDatum(tuple);SRF_RETURN_NEXT(funcctx, result);

实际实现根据业务需求的不同,要复杂的多,这里只是演示,所以简单这么一写。PG代码中有很多例子,搜索一下 SRF_IS_FIRSTCALL 可以发现很多。

6、完整示例

连起来看看我们的演示代码,会更清晰一些:

PG_FUNCTION_INFO_V1(quanzl_dummy_setof);Datumquanzl_dummy_setof(PG_FUNCTION_ARGS){  FuncCallContext *funcctx;  char ***values;  if (SRF_IS_FIRSTCALL())  {    TupleDesc tupdesc;    funcctx = SRF_FIRSTCALL_INIT();    oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);    tupdesc = CreateTemplateTupleDesc(2);    TupleDescInitEntry(tupdesc, (AttrNumber) 1, "col1",                 INT4OID, -1, 0);    TupleDescInitEntry(tupdesc, (AttrNumber) 2, "col2",                 INT4OID, -1, 0);    TupleDescInitEntry(tupdesc, (AttrNumber) 3, "col3",                 INT4OID, -1, 0);    funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);    ... 生成 values 的数据 ...    funcctx->user_fctx = values;    funcctx->max_calls = length of values;    MemoryContextSwitchTo(oldcontext);  }  funcctx = SRF_PERCALL_SETUP();  values = (char ***) funcctx->user_fctx;  if (funcctx->call_cntr < funcctx->max_calls)  {    tuple = BuildTupleFromCStrings(funcctx->attinmeta, values[funcctx->call_cntr]);    result = HeapTupleGetDatum(tuple);    SRF_RETURN_NEXT(funcctx, result);  }  else    SRF_RETURN_DONE(funcctx);}

返回结果集还有另一种写法,有时间再补充。

欢迎关注

存储过程返回结果集_PostgreSQL函数返回结果集相关推荐

  1. pandas使用groupby函数和count函数返回的是分组下每一列的统计值(不统计NaN缺失值)、如果多于一列返回dataframe、size函数返回分组下的行数结果为Series(缺失值不敏感)

    pandas使用groupby函数和count函数返回的是分组下每一列的统计值(不统计NaN缺失值).如果多于一列返回dataframe.size函数返回分组下的行数结果为Series(不区分缺失值和 ...

  2. “正话反说”:A和B在玩一个游戏,两人轮流说一句话,这句话正读反读都一样,如adgda,谁先说错,谁出局,另一个人胜出。编写一个函数用于判断这句话是否符合要求,符合要求时,函数返回1,否则函数返回0

    "正话反说":A和B在玩一个游戏,两人轮流说一句话,这句话正读反读都一样,如adgda,谁先说错,谁出局,另一个人胜出. 编写一个函数用于判断这句话是否符合要求,符合要求时,函数返 ...

  3. 模板引擎不关心内容之——art-template,碰见的同步与fs.readFile异步以及函数回调问题的描述,针对fs的readfille读取文件时,返回不了异步函数返回值的解决方法

    模板引擎不关心内容 art-template art-template不仅可以在浏览器使用,也可以在node中使用 npm install art-template该命令在哪执行就会把包下载在哪里,默 ...

  4. c语言自定义函数多个返回值,C语言函数返回值

    C语言函数返回值教程 如果,我们希望函数不返回任何值,那么我们需要显式的指明其返回类型为 C语言函数不返回值 语法 void funcName(paramType1 param1, paramType ...

  5. python函数能返回列表吗_Python函数返回列表还是作为生成器工作?

    我正在尝试创建一个返回对象或作为生成器的函数. 这是一个坏主意,因为作为一种最佳实践,您希望函数可靠地返回相同类型的值,但为了科学的利益-- 我正在使用Python 2,因此range返回一个列表,x ...

  6. c语言怎么返回数组,c++从函数返回数组的方法代码

    c++如何从函数返回数组? C++ 从函数返回数组 C++ 不允许返回一个完整的数组作为函数的参数.但是,您可以通过指定不带索引的数组名来返回一个指向数组的指针. 如果您想要从函数返回一个一维数组,您 ...

  7. mysql linux 函数返回值_linux recv函数返回值分析

    函数原型: ssize_t recv(int sockfd, void *buf, size_t len, int flags); 该函数第一个参数制定接收端套接字描述符; 第二个参数指明一个缓冲区, ...

  8. C++ opencv返回一幅图像返回以及vector作为函数返回值用法

    C++ opencv返回一幅图像返回 https://blog.csdn.net/mao_hui_fei/article/details/109349244 vector作为函数返回值用法 https ...

  9. c++_函数返回值,引用作为函数返回值

    catalog 函数返回值 返回值是`[const] T &` 返回值的类型是 T 返回的对象是 局部对象 实现原理 返回的对象是 全局对象 实例 函数返回值 返回值是[const] T &a ...

最新文章

  1. Python超越Java,Rust持续称王!Stack Overflow 2019开发者报告
  2. 7-2一元多项式的乘法与加法运算
  3. CopyOnWriteArrayList简介
  4. php 某一天时间凌晨,PHP获得今天 天凌晨时间戳的例子
  5. [云炬创业管理笔记]第二章成为创业者讨论4
  6. C# List.sort排序详解(多权重,升序降序)
  7. 统一元数据,数据湖Catalog让大数据存算分离不再是问题
  8. linux系统设置服务开机启动3种方法,Linux开机启动程序详解
  9. mysql 清空或删除表数据后,控制表自增列值的方法
  10. dos命令集--江南技术联盟
  11. POJ 3278(Catch That Cow)
  12. Android运行原理及运行机制知识汇总
  13. linux系统装psp,如何在Linux中玩PSP游戏
  14. 8086汇编实现 加密解密软件
  15. 非常哇塞的 SpringBoot性能优化长文!
  16. react骨架屏自动生成_网页骨架屏自动生成方案(dps)
  17. 除了LoRa和SigFox,物联网低功耗广域网络还有哪些
  18. java编写实现更新_Android实现APP自动更新功能
  19. supervisorctl error (no such process)
  20. python中文分词,生成标签云,生成指定形状图片标签云

热门文章

  1. php最难,那个PHP中号称最难的‘递归函数’
  2. c语言正则表达式库,c语言正则表达式库--PCRE
  3. 沙发家具网站源码_小户型装修不会选家具?大湾网推荐你了解这些装修风格家具,装修省心空间大!...
  4. CMake配置OpenCV时,显示错误:find_host_package(PythonInterp 2.7)' found wrong Python version
  5. gradle 刷新打包的时候报错
  6. vue npm run dev 报错 semver\semver.js:312 throw new TypeError('Invalid Version: ' + version)
  7. iView 实现可编辑表格 1
  8. MYSQL 浅谈MyISAM 存储引擎
  9. BZOJ 2738: 矩阵乘法 [整体二分]
  10. 初窥Javascript单元测试,附带掌握一门新技能的学习方式。