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_query
  PortalStart(portal, NULL, 0, InvalidSnapshot)

exec_bind_message
  PortalStart(portal, params, 0, InvalidSnapshot)

ExecuteQuery
  PortalStart(portal, paramLI, eflags, GetActiveSnapshot())

SPI_cursor_open_internal
  PortalStart(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的来源?

ExecuteQuery
  EvaluateParams
    // 准备计算参数表达式的值
    exprstates = ExecPrepareExprList(params, estate)
    
    makeParamList
      retval->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函数进入表达计算。

ExecScan
    for (;;)
        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。

ExecScan
    for (;;)
        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 $$
declare
  res int;
  c_04 CURSOR (p1 int, p2 int) FOR select b from tbl_01 where a = p1 and b = p2;
begin
  open c_04(2,200);
  fetch c_04 into res;
  raise notice '%',res;
end; $$;

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MMBench-Video:上海 AI Lab 联合多所高校推出长视频理解基准测试工具,全面评估 LVLMs 视频理解的能力

❤️ 如果你也关注大模型与 AI 的发展现状&#xff0c;且对大模型应用开发非常感兴趣&#xff0c;我会快速跟你分享最新的感兴趣的 AI 应用和热点信息&#xff0c;也会不定期分享自己的想法和开源实例&#xff0c;欢迎关注我哦&#xff01; &#x1f966; 微信公众号&#xff…

【万字详文介绍】:迭代扩张卷积神经网络(IDCNN)

&#x1f497;&#x1f497;&#x1f497;欢迎来到我的博客&#xff0c;你将找到有关如何使用技术解决问题的文章&#xff0c;也会找到某个技术的学习路线。无论你是何种职业&#xff0c;我都希望我的博客对你有所帮助。最后不要忘记订阅我的博客以获取最新文章&#xff0c;也欢…

(转载)Tools for Learning LLVM TableGen

前提 最近在学习有关llvm的东西&#xff0c;其中TableGen占了一部分&#xff0c;所以想特意学习下TableGen相关的语法。这里找到了LLVM官网的一篇介绍TableGen的博客&#xff0c;学习并使用机器翻译为中文。在文章的最后也添加了一些学习TableGen的资源。 原文地址&#xff1…

明源地产ERP WFWebService.asmx 反序列化RCE漏洞复现

0x01 产品简介 明源地产ERP是一款专为房地产行业设计的企业资源规划(ERP)系统,系统集成了项目管理、财务管理、客户关系管理、营销管理等多个模块,旨在帮助房地产企业提升运营效率、降低成本和提高客户满意度。它充分考虑了房地产行业的特性和需求,通过整合企业的各个业务…

AIGC时代LaTeX排版的应用、技巧与未来展望

文章目录 一、LaTeX简介与基础设置二、常用特殊符号与公式排版三、图片与表格的插入与排版四、自动编号与交叉引用五、自定义命令与样式六、LaTeX在AIGC时代的应用与挑战七、LaTeX的未来展望《LaTeX 入门实战》内容简介作者简介目录前言/序言读者对象本书内容充分利用本书 在AI…

redis:set集合命令,内部编码,使用场景

个人主页 &#xff1a; 个人主页 个人专栏 &#xff1a; 《数据结构》 《C语言》《C》《Linux》《网络》 《redis学习笔记》 文章目录 前言命令SADDSMEMBERSSISMEMBERSCARDSPOPSMOVESREM集合间操作SINTERSINTERSTORESUNIONSUNIONSTORESDIFFSDIFFSTORE 内部编码使用场景总结 前言…

智慧工地:引领工地管理和监测的革新

一、智慧工地是什么 智慧工地是智慧地球理念在工程领域的具体应用&#xff0c;是工程全生命周期管理的崭新理念。通过运用信息化手段&#xff0c;智慧工地利用三维设计平台对工程项目进行精确设计和施工模拟&#xff0c;重点关注施工过程管理&#xff0c;建立互联协同、智能生…

如何在Linux系统中使用Netcat进行网络调试

文章目录 Netcat简介安装Netcat在Debian/Ubuntu系统中安装在CentOS/RHEL系统中安装 Netcat基本命令Netcat基本用法示例1&#xff1a;监听端口示例2&#xff1a;连接到远程主机 Netcat选项-l选项-p选项-v选项 Netcat模式监听模式连接模式 Netcat排除和包含排除端口包含端口 Netc…

《AI产品经理手册》——解锁AI时代的商业密钥

在当今这个日新月异的AI时代&#xff0c;每一位产品经理都面临着前所未有的挑战与机遇&#xff0c;唯有紧跟时代潮流&#xff0c;深入掌握AI技术的精髓&#xff0c;才能在激烈的市场竞争中独占鳌头。《AI产品经理手册》正是这样一部为AI产品经理量身定制的实战宝典&#xff0c;…

多核架构的基本概念

目录 1.为什么使用多核 2.多核分类 2.1 同构和异构 2.2 SMP和AMP 3 小结 1.为什么使用多核 这个问题个人认为可以从两个方面来看&#xff1a; 性能问题 随着汽车ECU对集成化的要求越来越高&#xff0c;把多个ECU功能集中到一个多核MCU的需求也越来越明显。 以汽车制动…

NeurIPS 2024 | 机器人操纵世界模型来了,成功率超过谷歌RT-1 26.6%

对于人类而言&#xff0c;一旦掌握了 “打开瓶盖” 的动作&#xff0c;面对 “拧紧螺丝” 这样的任务通常也能游刃有余&#xff0c;因为这两者依赖于相似的手部动作。然而&#xff0c;对于机器人来说&#xff0c;即使是这样看似简单的任务转换依然充满挑战。例如&#xff0c;换…

OceanBase V4.3.3,首个面向实时分析场景的GA版本发布

在10月23日举办的 OceanBase年度发布会 上&#xff0c;我们怀着激动之情&#xff0c;正式向大家宣布了 OceanBase 4.3.3 GA 版的正式发布&#xff0c;这也是OceanBase 为实时分析&#xff08;AP&#xff09;场景打造的首个GA版本。 2024 年初&#xff0c;我们推出了 4.3.0 版本…

TS-AWG控制电光调制器:推动科技应用新发展的利器

一、电光调制有什么用&#xff1f; 如今&#xff0c;基于光学、光子学和脉冲激光以及电光调制器的应用正变得极为流行&#xff0c;最新一代科学家正在为其实际应用开辟新领域&#xff0c;如汽车激光雷达、医疗解决方案、航空航天和国防、量子和激光传感器。 测试挑战、上市时…

程序员开发速查表

作为一名苦逼的程序员&#xff0c;在开发的过程中&#xff0c;我们总是在各种编程语言中来回穿梭&#xff0c;忙完后端整前端&#xff0c;还得做一部分的运维工作&#xff0c;忙的我们有时候忘记语法&#xff0c;忘记编写规则&#xff0c;甚至混淆。这时候我们就希望有一个综合…

要在微信小程序中让一个 `view` 元素内部的文字水平垂直居中,可以使用 Flexbox 布局

文章目录 主要特点&#xff1a;基本用法&#xff1a;常用属性&#xff1a; 要在微信小程序中让一个 view 元素内部的文字水平垂直居中&#xff0c;可以使用 Flexbox 布局。以下是如何设置样式的示例&#xff1a; .scan-button {display: flex; /* 启用 Flexbox 布局 */justify…

docker pull 拉取镜像失败,使用Docker离线包

1、登录并注册Github&#xff0c;然后在Github中搜索并打开“wukongdaily/DockerTarBuilder” 项目&#xff0c;在该项目主页点击“Fork”。 然后点 “Create Fork”&#xff0c;将项目创建到自己的Github主页。 2、接着在自己创建过来的这个项目中点击“Actions” 3、然后…

基于Leaflet的自助标绘源码解析-其它对象解析

目录 前言 一、整体类图介绍 1、整体类图 二、进攻方向类对象标绘实现 1、基础配置 2、各组成部分的绘制 三、集结地对象的标绘实现 1、对象图形绘制 四、钳击对象的标绘实现 1、基础配置 2、各部分标绘 五、总结 前言 在之前的自助标绘相关博文中&#xff0c;我们…

基于机器学习的健身房会员健康风险分类及预测分析

1.项目背景 随着健康意识的提升和健身文化的普及&#xff0c;人们对科学健身和个性化训练的需求日益增长&#xff0c;健身房会员的锻炼模式和健康管理需求呈现出新的特点&#xff0c;本项目使用基于真实健身模式生成的973位会员数据进行深入分析&#xff0c;探索不同会员群体的…

如何在本地Linux服务器搭建WordPress网站结合内网穿透随时随地可访问

文章目录 前言1. 安装WordPress2. 创建WordPress数据库3. 安装相对URL插件4. 安装内网穿透发布网站4.1 命令行方式&#xff1a;4.2. 配置wordpress公网地址 5. 配置WordPress固定公网地址 前言 本文主要介绍如何在Linux Ubuntu系统上使用WordPress搭建一个本地网站&#xff0c…

30条勒索病毒处置原则

当前&#xff0c;勒索病毒在全球范围内肆虐&#xff0c;成为企业数据资产安全的头号威胁。这些狡猾的恶意软件&#xff0c;如同网络空间中的幽灵&#xff0c;不断寻找并利用系统的漏洞&#xff0c;通过加密数据或窃取敏感信息&#xff0c;向企业索取高额赎金。一旦感染&#xf…