Postgresql源码(82)SPI模块拆解分析一:执行简单SQL获取结果
相关
《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:生成执行计划
- BuildCachedPlan
- 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获取结果相关推荐
- Postgresql源码(83)执行器的结果接收系统——DestReceiver
相关 <Postgresql源码(76)执行器专用元组格式TupleTableSlot> <Postgresql源码(82)SPI模块拆解分析一:执行简单SQL获取结果> &l ...
- Postgresql源码(60)事务系统总结
相关 <Postgresql源码(23)Clog使用的Slru页面淘汰机制> <Postgresql源码(27)为什么事务提交会通过delayChkpt阻塞checkpoint> ...
- PostgreSQL源码分析
PostgreSQL源码结构 PostgreSQL的使用形态 PostgreSQL采用C/S(客户机/服务器)模式结构.应用层通过INET或者Unix Socket利用既定的协议与数据库服务器进行通信 ...
- Postgresql源码(85)查询执行——表达式解析器分析(select 1+1如何执行)
相关 <Postgresql源码(61)查询执行--最外层Portal模块> <Postgresql源码(62)查询执行--子模块ProcessUtility> <Pos ...
- postgreSQL源码分析——索引的建立与使用——Hash索引(3)
2021SC@SDUSC 上一篇博客讲了关于Hash索引创建与插入的相关函数,这一篇博客讲述关于溢出页的操作函数以及Hash表的扩展相关的函数. 目录 溢出页的分配和回收 _hash_addovflp ...
- postgreSQL源码分析——索引的建立与使用——各种索引类型的管理和操作(2)
2021SC@SDUSC 目录 上层操作函数 index_open index_beginscan() index_create() indexcmd.c 下层接口函数 IndexScanDescDa ...
- 【Android 10 源码】healthd 模块 HAL 2.0 分析
Android 9 引入了从 health@1.0 HAL 升级的主要版本 android.hardware.health HAL 2.0.这一新 HAL 具有以下优势: 框架代码和供应商代码之间的区 ...
- Postgresql源码(69)常规锁细节分析
相关: <Postgresql源码(40)Latch的原理分析和应用场景> <Postgresql源码(67)LWLock锁的内存结构与初始化> <Postgresql源 ...
- java ipc pgsql_[转]PostgreSQL源码结构
PostgreSQL采用C/S(客户机/服务器)模式结构.应用层通过INET或者Unix Socket利用既定的协议与数据库服务器进行通信. 另外,还有一种'Standalone Backend'使用 ...
最新文章
- vue判断浏览器是否id_QQ被曝读取浏览器历史记录!回应称系用于判断是否恶意登录...
- python处理数据的优势-python处理excel的优势是什么
- ElasticSearch配置优先使用自带jdk
- SLAM知识[7]:依赖项和安装
- NYOJ 594 还是A+B
- html5有哪些新特性、移除了那些元素?如何处理HTML5新标签的浏览器兼容问题?如何区分 HTML 和 HTML5?...
- php http请求xml数据,使用php从HTTP POST请求中检索XML
- MySQL数据库服务器搭建及基本管理
- golang mysql遇到的一些问题记录和解决
- 【蓝桥杯单片机】矩阵键盘和独立键盘新解(更稳定更高复用性)
- gcc中的结构体成员位域
- java泛型 之 入门(interface)
- 6.1 统计学基本原理
- Mysql中LENGTH()函数
- i3处理器_千元英特尔10代I3处理器套装跑分72万?微星差异化赢得市场
- QQ群共享总是下载失败怎么解决?
- 常用icon以及color颜色RGB值和对应颜色效果图
- Java程序员必看的15本书的电子版下载地址
- VMware XP安装安装程序没有找到硬盘驱动器
- c++ 泛型 之 TypeTraints
热门文章
- 【MD】Markdown常用语法
- Postman使用技巧之Authorization使用
- linux rm 命令详解,Linux rm命令使用指南
- Cookie详解与跨域问题
- ElasticSearch最新版(8.4.3) IK分词器基于mysql实现热更新词库
- Ae 入门系列之十:关键帧动画进阶
- Codeforces 908 B. New Year and Buggy Bot
- 消防管件做的机器人图片_西安建筑工人用消防管件组装成机器人 可监测PM值会喷淋...
- 垃圾分类在计算机上的重要性,垃圾分类的意义和垃圾的好处好处
- vue+css漂亮的定制日历