相关
《Postgresql源码(76)执行器专用元组格式TupleTableSlot》
《Postgresql源码(82)SPI模块拆解分析一:执行简单SQL获取结果》
《Postgresql源码(83)执行器的结果接收系统——DestReceiver》

SPI简单用例初步分析

1 用例:外挂C函数调用SPI

直接执行:

cat << EOF > spitest.c
#include "postgres.h"
#include "executor/spi.h"
#include "utils/builtins.h"
#include "fmgr.h"PG_MODULE_MAGIC;
PG_FUNCTION_INFO_V1(sptest1);Datum
sptest1(PG_FUNCTION_ARGS)
{char *sql10 = "select s from generate_series(1,10) s";int ret;int proc;SPI_connect();ret = SPI_exec(sql10, 0);proc = SPI_processed;SPI_finish();return (proc);
}
EOFgcc -O0 -Wall -I /home/mingjiegao/dev/src/postgres/src/include -g -shared -fpic -o spitest.so spitest.c

psql执行:

create or replace function sptest1()
returns int8
as '/home/mingjiegao/tmp/spitest/spitest.so', 'sptest1' language C STRICT;  -- 调用函数
postgres=# select sptest1();sptest1
---------10
(1 row)

2 执行分析

SPI几个内部全局变量的含义

static _SPI_connection *_SPI_stack = NULL;
static _SPI_connection *_SPI_current = NULL;
static int  _SPI_stack_depth = 0;  /* allocated size of _SPI_stack */
static int  _SPI_connected = -1;   /* current stack index */
  • _SPI_stack:栈指针(数组):第一次16个conn、第二次32个conn、第三次64个conn。
  • _SPI_current:当前活跃conn。
  • _SPI_stack_depth:当前栈深入,第一次16、第二次32、第三次64。
  • _SPI_connected:当前活跃conn的索引。

2.1 SPI_connect

栈中申请一个conn位置,用_SPI_current指向,然后初始化结构体变量。

int
SPI_connect(void)
{return SPI_connect_ext(0);
}int
SPI_connect_ext(int options)
{int            newdepth;

维护栈大小,如果栈还有空间,直接使用;如果就剩一个conn了,扩到原来的一倍。

比如:如果栈已经使用了15个conn,下次就要使用第16个conn了,就开始扩容,扩到32个。

 /* Enlarge stack if necessary */if (_SPI_stack == NULL){if (_SPI_connected != -1 || _SPI_stack_depth != 0)elog(ERROR, "SPI stack corrupted");newdepth = 16;_SPI_stack = (_SPI_connection *)MemoryContextAlloc(TopMemoryContext,newdepth * sizeof(_SPI_connection));_SPI_stack_depth = newdepth;}else{if (_SPI_stack_depth <= 0 || _SPI_stack_depth <= _SPI_connected)elog(ERROR, "SPI stack corrupted");if (_SPI_stack_depth == _SPI_connected + 1){newdepth = _SPI_stack_depth * 2;_SPI_stack = (_SPI_connection *)repalloc(_SPI_stack,newdepth * sizeof(_SPI_connection));_SPI_stack_depth = newdepth;}}/* Enter new stack level */_SPI_connected++;Assert(_SPI_connected >= 0 && _SPI_connected < _SPI_stack_depth);_SPI_current = &(_SPI_stack[_SPI_connected]);_SPI_current->processed = 0;_SPI_current->tuptable = NULL;_SPI_current->execSubid = InvalidSubTransactionId;slist_init(&_SPI_current->tuptables);_SPI_current->procCxt = NULL;    /* in case we fail to create 'em */_SPI_current->execCxt = NULL;_SPI_current->connectSubid = GetCurrentSubTransactionId();_SPI_current->queryEnv = NULL;_SPI_current->atomic = (options & SPI_OPT_NONATOMIC ? false : true);_SPI_current->internal_xact = false;_SPI_current->outer_processed = SPI_processed;_SPI_current->outer_tuptable = SPI_tuptable;_SPI_current->outer_result = SPI_result;
  • 创建"SPI Proc"上下文记录到:_SPI_current->procCxt
  • 创建"SPI Exec"上下文记录到:_SPI_current->execCxt
  • 切换到"SPI Proc"
 _SPI_current->procCxt = AllocSetContextCreate(_SPI_current->atomic ? TopTransactionContext : PortalContext,"SPI Proc",ALLOCSET_DEFAULT_SIZES);_SPI_current->execCxt = AllocSetContextCreate(_SPI_current->atomic ? TopTransactionContext : _SPI_current->procCxt,"SPI Exec",ALLOCSET_DEFAULT_SIZES);/* ... and switch to procedure's context */_SPI_current->savedcxt = MemoryContextSwitchTo(_SPI_current->procCxt);/** Reset API global variables so that current caller cannot accidentally* depend on state of an outer caller.*/SPI_processed = 0;SPI_tuptable = NULL;SPI_result = 0;return SPI_OK_CONNECT;
}

2.2 SPI_exec

/* Parse, plan, and execute a query string */
int
SPI_execute(const char *src, bool read_only, long tcount)
{_SPI_plan  plan;SPIExecuteOptions options;int          res;if (src == NULL || tcount < 0)return SPI_ERROR_ARGUMENT;
  • _SPI_begin_call切换到exec状态:切换上下文到SPI Exec
 res = _SPI_begin_call(true);if (res < 0)return res;memset(&plan, 0, sizeof(_SPI_plan));plan.magic = _SPI_PLAN_MAGIC;plan.parse_mode = RAW_PARSE_DEFAULT;plan.cursor_options = CURSOR_OPT_PARALLEL_OK;
  • 执行raw_parser
  • 执行CreateOneShotCachedPlan
 _SPI_prepare_oneshot_plan(src, &plan);memset(&options, 0, sizeof(options));options.read_only = read_only;options.tcount = tcount;
  • pg_analyze_and_rewrite:分析重写
  • CompleteCachedPlan
  • GetCachedPlan
    • BuildCachedPlan

      • pg_plan_queries:生成执行计划
  • PushActiveSnapshot
  • CreateDestReceiver:创建接收器,指定SPI接收器
  • CreateQueryDesc:给执行器创建执行描述符
  • _SPI_pquery:DML使用Executor执行查询
    • ExecutorStart
    • ExecutorRun
    • ExecutorFinish
    • ExecutorEnd
 res = _SPI_execute_plan(&plan, &options,InvalidSnapshot, InvalidSnapshot,true);_SPI_end_call(true);return res;
}

Postgresql源码(82)SPI模块拆解分析一:执行简单SQL获取结果相关推荐

  1. Postgresql源码(83)执行器的结果接收系统——DestReceiver

    相关 <Postgresql源码(76)执行器专用元组格式TupleTableSlot> <Postgresql源码(82)SPI模块拆解分析一:执行简单SQL获取结果> &l ...

  2. Postgresql源码(60)事务系统总结

    相关 <Postgresql源码(23)Clog使用的Slru页面淘汰机制> <Postgresql源码(27)为什么事务提交会通过delayChkpt阻塞checkpoint> ...

  3. PostgreSQL源码分析

    PostgreSQL源码结构 PostgreSQL的使用形态 PostgreSQL采用C/S(客户机/服务器)模式结构.应用层通过INET或者Unix Socket利用既定的协议与数据库服务器进行通信 ...

  4. Postgresql源码(85)查询执行——表达式解析器分析(select 1+1如何执行)

    相关 <Postgresql源码(61)查询执行--最外层Portal模块> <Postgresql源码(62)查询执行--子模块ProcessUtility> <Pos ...

  5. postgreSQL源码分析——索引的建立与使用——Hash索引(3)

    2021SC@SDUSC 上一篇博客讲了关于Hash索引创建与插入的相关函数,这一篇博客讲述关于溢出页的操作函数以及Hash表的扩展相关的函数. 目录 溢出页的分配和回收 _hash_addovflp ...

  6. postgreSQL源码分析——索引的建立与使用——各种索引类型的管理和操作(2)

    2021SC@SDUSC 目录 上层操作函数 index_open index_beginscan() index_create() indexcmd.c 下层接口函数 IndexScanDescDa ...

  7. 【Android 10 源码】healthd 模块 HAL 2.0 分析

    Android 9 引入了从 health@1.0 HAL 升级的主要版本 android.hardware.health HAL 2.0.这一新 HAL 具有以下优势: 框架代码和供应商代码之间的区 ...

  8. Postgresql源码(69)常规锁细节分析

    相关: <Postgresql源码(40)Latch的原理分析和应用场景> <Postgresql源码(67)LWLock锁的内存结构与初始化> <Postgresql源 ...

  9. java ipc pgsql_[转]PostgreSQL源码结构

    PostgreSQL采用C/S(客户机/服务器)模式结构.应用层通过INET或者Unix Socket利用既定的协议与数据库服务器进行通信. 另外,还有一种'Standalone Backend'使用 ...

最新文章

  1. vue判断浏览器是否id_QQ被曝读取浏览器历史记录!回应称系用于判断是否恶意登录...
  2. python处理数据的优势-python处理excel的优势是什么
  3. ElasticSearch配置优先使用自带jdk
  4. SLAM知识[7]:依赖项和安装
  5. NYOJ 594 还是A+B
  6. html5有哪些新特性、移除了那些元素?如何处理HTML5新标签的浏览器兼容问题?如何区分 HTML 和 HTML5?...
  7. php http请求xml数据,使用php从HTTP POST请求中检索XML
  8. MySQL数据库服务器搭建及基本管理
  9. golang mysql遇到的一些问题记录和解决
  10. 【蓝桥杯单片机】矩阵键盘和独立键盘新解(更稳定更高复用性)
  11. gcc中的结构体成员位域
  12. java泛型 之 入门(interface)
  13. 6.1 统计学基本原理
  14. Mysql中LENGTH()函数
  15. i3处理器_千元英特尔10代I3处理器套装跑分72万?微星差异化赢得市场
  16. QQ群共享总是下载失败怎么解决?
  17. 常用icon以及color颜色RGB值和对应颜色效果图
  18. Java程序员必看的15本书的电子版下载地址
  19. VMware XP安装安装程序没有找到硬盘驱动器
  20. c++ 泛型 之 TypeTraints

热门文章

  1. 【MD】Markdown常用语法
  2. Postman使用技巧之Authorization使用
  3. linux rm 命令详解,Linux rm命令使用指南
  4. Cookie详解与跨域问题
  5. ElasticSearch最新版(8.4.3) IK分词器基于mysql实现热更新词库
  6. Ae 入门系列之十:关键帧动画进阶
  7. Codeforces 908 B. New Year and Buggy Bot
  8. 消防管件做的机器人图片_西安建筑工人用消防管件组装成机器人 可监测PM值会喷淋...
  9. 垃圾分类在计算机上的重要性,垃圾分类的意义和垃圾的好处好处
  10. vue+css漂亮的定制日历