Postgresql源码(137)执行器参数传递与使用

参考
《Postgresql源码(127)投影ExecProject的表达式执行分析》

0 总结速查

prepare p_04(int,int) as select b from tbl_01 where a = $1 and b = $2为例。

  • custom计划中,在表达式计算中使用参数的值,因为custom计划会带参数值,所以表达式计算时不需要从参数列表中取值,直接EEO_CASE(EEOP_FUNCEXPR_STRICT)计算即可。
  • generic计划中,在表达式计算中使用参数的值,generic计划不带参数值,所以需要多走一步EEO_CASE(EEOP_PARAM_EXTERN)、EEO_CASE(EEOP_FUNCEXPR_STRICT)。具体调用ExecEvalParamExtern函数拿到参数值。
  • generic计划中,使用参数的节点会放一个Param。

1 执行器如何使用参数?

在下面例子中,execute语句执行时带了两个参数,执行器是在哪里带入参数执行的?下面做一些分析。

prepare p_04(int,int) as select b from tbl_01 where a = $1 and b = $2;
execute p_04(2,200);

带入参数的位置是PortalStart函数。

extern void PortalStart(Portal portal, ParamListInfo params, int eflags, Snapshot snapshot);

PortalStart的第二个参数可以接受参数列表ParamListInfo,从代码上看,PortalStart有三处调用位置:

exec_simple_queryPortalStart(portal, NULL, 0, InvalidSnapshot)exec_bind_messagePortalStart(portal, params, 0, InvalidSnapshot)ExecuteQueryPortalStart(portal, paramLI, eflags, GetActiveSnapshot())SPI_cursor_open_internalPortalStart(portal, paramLI, 0, snapshot)
  1. exec_simple_query:执行简单SQL语句,不需要传参。
  2. exec_bind_message:PEB协议中的B阶段,绑定参数。
  3. ExecuteQuery:SQL语法提供的PBE协议,在execute阶段,绑定参数。
  4. SPI_cursor_open_internal:PL中打开游标时,绑定参数。

下面对3、4两种情况展开分析。

2 execute执行时执行器的传参

栗子:

create table tbl_01(a int, b int);
insert into tbl_01 values (1,100);
insert into tbl_01 values (2,200);
prepare p_04(int,int) as select b from tbl_01 where a = $1 and b = $2;
execute p_04(2,200);

execute p_04(2,200); 执行时,PortalStart会带入ParamListInfo。
在这里插入图片描述

2.1 问题一:ParamListInfo的来源?

ExecuteQueryEvaluateParams// 准备计算参数表达式的值exprstates = ExecPrepareExprList(params, estate)makeParamListretval->parserSetup = paramlist_parser_setup// paramlist_parser_setup//   pstate->p_paramref_hook = paramlist_param_ref//// paramlist_param_ref//   param = makeNode(Param)//   param->paramkind = PARAM_EXTERN//   param->paramid = paramno//   ...//   钩子函数中生成Param,该实例不会走这个钩子,注意Param结构是不带值的,只用于中间过程。// 走表达式计算参数的值// 注意值都在paramLI->params[i]->value中i = 0;foreach(l, exprstates){ExprState  *n = (ExprState *) lfirst(l);ParamExternData *prm = &paramLI->params[i];prm->ptype = param_types[i];prm->pflags = PARAM_FLAG_CONST;prm->value = ExecEvalExprSwitchContext(n,GetPerTupleExprContext(estate),&prm->isnull);i++;}

生成ParamListInfo(包含参数的全部信息,包括值)

paramLI = {paramFetch = 0x0,paramFetchArg = 0x0,paramCompile = 0x0,paramCompileArg = 0x0,parserSetup = 0x8357c1 <paramlist_parser_setup>,parserSetupArg = 0x3238da8,paramValuesStr = 0x0,numParams = 2,params = 0x3238de8}

2.2 问题二:ParamListInfo的使用位置?

custom plan

前五次执行会生成customplan,customplan在GetCachedPlan中生成,customplan计划是带着参数生成的(按参数定制的计划,更准确,但每次参数变了都要重新生成),所以计划中会有参数的具体值,执行时不会使用执行器带入的ParamListInfo。
在这里插入图片描述
构造customplan时,会带入参数生成计划:
在这里插入图片描述

ExecQual调用表达式框架计算where a = $1 and b = $2,ExecQual函数进入表达计算。

ExecScanfor (;;)slot = ExecScanFetch...if (qual == NULL || ExecQual(qual, econtext))...return slot

ExecQual表达式计算流程:

  1. EEO_CASE(EEOP_SCAN_FETCHSOME)
    • 从econtext->ecxt_scantuple读取到scanslot(当前要处理的一行数据)slot_getsomeattrs函数确保这一行数据中,至少有op->d.fetch.last_var个列是可以直接访问的。《Postgresql源码(127)投影ExecProject的表达式执行分析》
  2. EEO_CASE(EEOP_SCAN_VAR)
    • 从行中拿到需要列的值。《Postgresql源码(127)投影ExecProject的表达式执行分析》
  3. EEO_CASE(EEOP_FUNCEXPR_STRICT)
    • 计算where中第一个条件
    • fcinfo : int4eq
    • arg1 : 2
    • arg2 : 2
  4. EEO_CASE(EEOP_QUAL)
  5. EEO_CASE(EEOP_FUNCEXPR_STRICT)
    • 计算where中第二个条件
    • fcinfo : int4eq
    • arg1 : 200
    • arg2 : 200
  6. EEO_CASE(EEOP_QUAL)

generic plan

第六次执行时,choose_custom_plan返回false,BuildCachedPlan时没有传入任何参数构造generic plan(通用执行计划,可以接受任何参数,不用每次都生成计划,但没有customplan精确,毕竟这里没有给参数)
在这里插入图片描述
执行execute p_04(2,200);给的两个参数明显是用于过滤条件的,所以在ExecScan→ExecQual中寻找使用的位置:
在这里插入图片描述

在ExecEvalParamExtern函数中,从econtext->ecxt_param_list_info中拿到参数值,返回给表达式框架:

ExecEvalParamExtern(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
{ParamListInfo paramInfo = econtext->ecxt_param_list_info;int			paramId = op->d.param.paramid;if (likely(paramInfo &&paramId > 0 && paramId <= paramInfo->numParams)){ParamExternData *prm;ParamExternData prmdata;......prm = &paramInfo->params[paramId - 1];......*op->resvalue = prm->value;*op->resnull = prm->isnull;return;}}......
}

最终ExecScan在loop中,拿到的slot经过ExecQual的计算,决定是否保留该元组。

ExecQual调用表达式框架计算where a = $1 and b = $2,通过ExecEvalParamExtern函数拿到$1$2的值,完成计算,放回true OR false。

ExecScanfor (;;)slot = ExecScanFetch...if (qual == NULL || ExecQual(qual, econtext))...return slot

表达式计算流程:

  1. EEO_CASE(EEOP_SCAN_FETCHSOME)
  2. EEO_CASE(EEOP_SCAN_VAR)
  3. EEO_CASE(EEOP_PARAM_EXTERN)
  4. EEO_CASE(EEOP_FUNCEXPR_STRICT)
    • int4eq
    • arg1 : 2
    • arg2 : 2
  5. EEO_CASE(EEOP_QUAL)
  6. EEO_CASE(EEOP_SCAN_VAR)
  7. EEO_CASE(EEOP_PARAM_EXTERN)
  8. EEO_CASE(EEOP_FUNCEXPR_STRICT)
    • int4eq
    • arg1 : 200
    • arg2 : 200

从计划上来看,参数的位置是两个Param。
在这里插入图片描述

3 游标打开时执行器的传参

create table tbl_01(a int, b int);
insert into tbl_01 values (1,100);
insert into tbl_01 values (2,200);do $$
declareres int;c_04 CURSOR (p1 int, p2 int) FOR select b from tbl_01 where a = p1 and b = p2;
beginopen c_04(2,200);fetch c_04 into res;raise notice '%',res;
end; $$;

PL的参数在transform阶段已经转成const了,所以执行类似customplan:
在这里插入图片描述

fetch堆栈:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/59252.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SPI通信详解-学习笔记

参考原文地址 SPI&#xff1a;高速、全双工&#xff0c;同步、通信总线 SPI主从模式 SPI分为主、从两种模式&#xff0c;一个SPI通讯系统需要包含一个&#xff08;且只能是一个&#xff09;主设备&#xff0c;一个或多个从设备。提供时钟的为主设备&#xff08;Master&#xff…

Day102漏洞发现-漏扫项目篇Poc开发Yaml语法插件一键生成匹配结果交互提取

知识点&#xff1a; 1、Nuclei-Poc开发-环境配置&编写流程 2、Nuclei-Poc开发-Yaml语法&匹配提取 3、Nuclei-Poc开发-BurpSuite一键生成插件 Nuclei-Poc开发-环境配置&编写流程 1、开发环境&#xff1a;VscodeYaml插件 Visual Studio Code - Code Editing. R…

Redis 初学者指南

Redis 初学者指南 1. 什么是 Redis&#xff1f;2. Redis 的基本概念3. 安装 Redis3.1 使用 Docker 安装3.2 从源码编译安装 4. 基本操作4.1 启动 Redis 服务4.2 连接 Redis 客户端4.3 常用命令 5. Redis 的数据结构5.1 字符串5.2 列表5.3 集合5.4 散列5.5 有序集合 6. 高级特性…

如何封装一个axios,封装axios有哪些好处

什么是Axios Axios 是一个基于 Promise 的 HTTP 客户端&#xff0c;用于在浏览器和 Node.js 中发送异步网络请求。它简化了发送 GET、POST、PUT、DELETE 等请求的过程&#xff0c;并且支持请求拦截、响应拦截、取消请求和自动处理 JSON 数据等功能。 为什么要封装Axios 封装…

Node.js 入门指南:从零开始构建全栈应用

​&#x1f308;个人主页&#xff1a;前端青山 &#x1f525;系列专栏&#xff1a;node.js篇 &#x1f516;人终将被年少不可得之物困其一生 依旧青山,本期给大家带来node.js篇专栏内容:node.js-入门指南&#xff1a;从零开始构建全栈应用 前言 大家好&#xff0c;我是青山。作…

WordPress网站添加嵌入B站视频,自适应屏幕大小,取消自动播放

结合bv号 改成以下嵌入式代码&#xff08;自适应屏幕大小,取消自动播放&#xff09; <iframe style"width: 100%; aspect-ratio: 16/9;" src"//player.bilibili.com/player.html?isOutsidetrue&bvidBV13CSVYREpr&p1&autoplay0" scrolling…

大模型应用系列:Query 变换的示例浅析

【引】NLP中的经典组件在大模型应用中还有效么&#xff1f;大模型对自然语言处理中的典型任务有什么影响么&#xff1f; RAG应用通过分割文档、嵌入向量化并检索高语义相似性的块来响应用户问题&#xff0c;但面临文档块不相关、用户用词不当及结构化查询需求等问题。若RAG无法…

【Oracle】空格单字符通配符查询匹配失败

问题 在进行模糊查询的时候&#xff0c;通过全局任意字符串匹配出含有两个字刘姓的人&#xff0c;但是通过刘_不能匹配出结果。 解决 检查后发现&#xff0c;姓名中包含空格 SELECT * FROM student WHERE TRIM(sname) LIKE 刘_;第一种解决方案就是查询的时候进行去空格处理&a…

讲讲⾼并发的原则?

大家好&#xff0c;我是锋哥。今天分享关于【讲讲⾼并发的原则&#xff1f;】面试题。希望对大家有帮助&#xff1b; 讲讲⾼并发的原则&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 高并发是指系统在同一时间内能够处理大量请求的能力。要有效地管理…

鸿蒙进阶-AlphabetIndexer组件

大家好&#xff0c;这里是鸿蒙开天组&#xff0c;今天我们来学习AlphabetIndexer组件&#xff0c;喜欢就点点关注吧&#xff01; 通过 AlphabetIndexer 组件可以与容器组件结合&#xff0c;实现导航联动&#xff0c;以及快速定位的效果 核心用法 AlphabetIndexer不是容器组件…

WebGL(Web Graphics Library)

WebGL&#xff08;Web Graphics Library&#xff09;是一种基于 JavaScript 的 API&#xff0c;允许在网页上渲染高性能的 2D 和 3D 图形。它利用计算机的 GPU 来实现硬件加速&#xff0c;因此适合创建游戏、数据可视化和交互式应用程序。 WebGL 的基本概念&#xff1a; 上下文…

nvm使用的方法

nvm——Node版本管理工具_node管理工具-CSDN博客

第四部分 可扩展的架构实践

第四部分 可扩展的架构实践 19. 第19章 对架构影响重大的需求20. 第20章 设计架构21. 第21章 评估架构22. 第22章 记录架构23. 第23章 管理架构债

ubuntu交叉编译expat库给arm平台使用

1.下载expat库源码: https://github.com/libexpat/libexpat/release?page=2 wget https://github.com/libexpat/libexpat/release/download/R_2_3_0/expat-2.3.0.tar.bz2 下载成功: 2.解压expat库,并进入解压后的目录: tar xjf expat-2.3.0.tar.bz2 cd expat-2.3.0 <…

Python中的PDF处理工具:PyPDF2和ReportLab使用指南

Python中的PDF处理工具&#xff1a;PyPDF2和ReportLab使用指南 在日常工作和项目中&#xff0c;PDF 文件处理是个常见需求&#xff0c;不论是合并报告、加密文档、填充表单&#xff0c;还是生成发票。Python 中有许多用于操作 PDF 文件的库&#xff0c;其中 PyPDF2 和 ReportL…

【系统面试篇】进程和线程类(1)(笔记)——区别、通讯方式、同步、互斥、锁分类

目录 一、问题综述 1. 进程和线程的区别&#xff1f; 2. 进程的状态有哪些&#xff1f; 3. 进程之间的通信方式? &#xff08;1&#xff09;管道 &#xff08;2&#xff09;消息队列 &#xff08;3&#xff09;共享内存 &#xff08;4&#xff09;信号量 &#xff08…

delphi 编译多语言工程 error RC2104 : undefined keyword or key name:

Delphi 10.3中建立多语言工程&#xff0c;编译时出现错误&#xff1a;error RC2104 : undefined keyword or key name: 出现错误的的文件是.rc文件&#xff0c;出现错误的位置是 System_JSONConsts_SInvalidJavascriptQuote, L"Invalid JavaScript string quote character…

vue 禁用element-ui calendar 取消非本月日期的点击事件

需求描述&#xff1a;原本的日历组件不是本月的日期是灰色的&#xff0c;且点击后会跳转到对应的月份&#xff0c;现在不想它跳转&#xff0c;需要禁用它的点击事件 方法&#xff1a;使用css的pointer-events:none属性即可&#xff0c;把不是当前月份的日历表格的td属性修改 :…

nginx(四):如何在 Nginx 中配置以保留真实 IP 地址

如何在 Nginx 中配置以保留真实 IP 地址 1、概述2、nginx配置示例2.1、配置说明2.2、客户端获取真实IP2.2.1、代码说明 3、插曲4、总结 大家好&#xff0c;我是欧阳方超&#xff0c;可以我的公众号“欧阳方超”&#xff0c;后续内容将在公众号首发。 1、概述 当使用nginx作为…

传统的自然语言处理评估指标

目录 传统的自然语言处理评估指标 EM(Exact Match) BLEU(Bilingual Evaluation Understudy) 传统的自然语言处理评估指标 传统评估指标 EM(Exact Match) 计算方式:如果生成的答案与参考答案完全相同(字符级完全匹配),则 EM 得分为 1,否则为 0。这是一种比较严格的…