PostgreSQL源码standard_ExecutorStart

news/2025/3/14 17:49:54/
standard_ExecutorStart(QueryDesc *queryDesc, int eflags)

queryDesc 是一个指向 QueryDesc 结构的指针。QueryDesc 结构包含了执行查询所需的上下文信息,包括查询计划、参数值、结果集等。
eflags 是一个整数参数,代表执行标志(execution flags)。这个参数用于指定执行查询时的一些选项和行为。通过指定不同的标志,可以影响查询的执行方式和结果。

一些常见的 eflags 标志包括:

EXEC_FLAG_EXPLAIN_ONLY:表示仅执行查询计划的解释,并不实际执行查询。
EXEC_FLAG_WITH_NO_DATA:表示查询执行不需要返回结果集。
EXEC_FLAG_WITHOUT_OIDS:表示查询执行不需要返回对象标识符。
EXEC_FLAG_REWIND:表示执行查询前需要将游标或扫描器重置到起始位置。
通过指定不同的标志,可以根据具体需求对查询的执行行为进行控制和调整。

/* 如果事务是只读的,我们需要检查是否计划对非临时表进行写操作。EXPLAIN 被视为只读。不允许在并行模式下进行写操作。支持 UPDATE 和 DELETE 将需要
(a)在共享内存中存储组合 CID 哈希,而不是仅在并行性开始时同步它一次
(b)为了互斥,heap_update() 对 xmax 的依赖性的替代。
INSERT 可能没有这些问题,但我们禁止它以简化检查。在 CommandCounterIncrement 和其他地方,我们对在并行模式下执行不安全操作有更低级别的防御措施,但这样可以提供更用户友好的错误消息。 */
if ((XactReadOnly || IsInParallelMode()) && !(eflags & EXEC_FLAG_EXPLAIN_ONLY))ExecCheckXactReadOnly(queryDesc->plannedstmt);

Estate是一个执行状态的结构,用于跟踪和管理查询执行的状态和上下文。它包含了执行查询所需的各种信息,如查询计划、参数值、结果集等。构建 EState 是为了在执行过程中管理和操作这些信息。

// 构建 EState,切换到每个查询的内存上下文以进行启动阶段。
estate = CreateExecutorState();
queryDesc->estate = estate;

在启动阶段,需要构建 EState 对象,并将内存上下文切换到每个查询的内存上下文,以便为查询执行提供独立的内存环境和隔离性。这有助于确保查询的执行过程在正确的上下文环境中进行,并避免与其他查询的冲突。

//其作用是切换当前的内存上下文到 estate->es_query_cxt 上下文。
oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);

通过切换内存上下文,当前的内存分配和回收操作将在 estate->es_query_cxt 上下文中进行,这意味着在查询执行期间分配的内存将在该上下文中进行管理。同时,原来的内存上下文会被保存到 oldcontext 变量中,以便在适当的时候可以恢复回来。

// 从 queryDesc 填充外部参数(如果有),并为内部参数分配工作空间
estate->es_param_list_info = queryDesc->params;

外部参数是由外部环境传递给查询的参数,如客户端传递的查询参数。
内部参数是在查询执行期间内部使用的参数,通常用于在查询计划的不同阶段传递信息或状态。

// 如果 queryDesc->plannedstmt->paramExecTypes 不是空列表(NIL)
if (queryDesc->plannedstmt->paramExecTypes != NIL)
{int nParamExec;// 获取 queryDesc->plannedstmt->paramExecTypes 列表的长度,即外部参数的数量,并将结果保存在 nParamExec 变量中。nParamExec = list_length(queryDesc->plannedstmt->paramExecTypes);// 分配一个大小为 nParamExec * sizeof(ParamExecData) 的内存空间,并将其初始化为零。// 这里使用了 palloc0 函数来分配内存,并确保所分配的内存中的内容为零。// 将分配的内存空间的起始地址赋值给 estate->es_param_exec_vals,即执行状态结构 estate 中的 es_param_exec_vals 成员。// es_param_exec_vals 是一个指向 ParamExecData 结构的指针,用于存储外部参数的执行数据。estate->es_param_exec_vals = (ParamExecData *) palloc0(nParamExec * sizeof(ParamExecData));
}

通过执行以上操作,为执行状态结构 estate 中的 es_param_exec_vals 成员分配了足够的内存空间,用于存储外部参数的执行数据。这样,在查询执行过程中可以使用这些数据来替换查询计划中的参数,并传递给执行器进行实际的查询操作。

/* 现在我们要求所有的调用者提供 sourceText */
Assert(queryDesc->sourceText != NULL);
// estate 结构中的 es_sourceText 将包含调用者提供的查询文本。
estate->es_sourceText = queryDesc->sourceText;

确保了调用者在使用这段代码或函数时必须提供有效的 sourceText 参数。这可以防止潜在的错误或信息不完整的情况,并在需要时提供准确的查询文本信息。

// 从 queryDesc 填充查询环境(如果有的话)
estate->es_queryEnv = queryDesc->queryEnv;

查询环境(query environment)是一组与查询相关的环境变量或上下文信息的集合。它包括一些查询执行所需的上下文信息,如当前数据库、当前用户、事务状态等。

// 如果是非只读查询,设置命令ID以标记输出元组
switch (queryDesc->operation){case CMD_SELECT:// CTE 公共表达式/** 对于带有 SELECT FOR [KEY] UPDATE/SHARE 或修改 CTE 的 SELECT 语句,* 需要标记元组。* 通过调用 GetCurrentCommandId(true) 获取当前命令的命令ID,并将其赋值给 estate 结构中的 es_output_cid 成员。*/if (queryDesc->plannedstmt->rowMarks != NIL ||queryDesc->plannedstmt->hasModifyingCTE)estate->es_output_cid = GetCurrentCommandId(true);/** 没有修改 CTE 的 SELECT 语句不可能有触发器队列,* 所以强制跳过触发器模式。这只是一个边缘的效率优化技巧,* 因为 AfterTriggerBeginQuery/AfterTriggerEndQuery 并不是非常耗费资源,* 但是我们可以这样做。*//* 对于没有修改 CTE 的 SELECT 语句,由于不可能有触发器队列的情况,为了提高效率,将执行标志 eflags 设置为 EXEC_FLAG_SKIP_TRIGGERS,跳过触发器模式。*/if (!queryDesc->plannedstmt->hasModifyingCTE)eflags |= EXEC_FLAG_SKIP_TRIGGERS;break;/* * 对于 CMD_INSERT(插入)、CMD_DELETE(删除)和 CMD_UPDATE(更新)操作,* 同样将当前命令的命令ID赋值给 estate 结构中的 es_output_cid 成员*/case CMD_INSERT:case CMD_DELETE:case CMD_UPDATE:estate->es_output_cid = GetCurrentCommandId(true);break;// 对于其他未知的操作类型,将会抛出一个错误,报告无法识别的操作代码default:elog(ERROR, "unrecognized operation code: %d",(int) queryDesc->operation);break;}
/*
设置一个 AFTER 触发器语句上下文,除非被告知不要设置,或者在仅进行 EXPLAIN 的模式下(此时不会调用 ExecutorFinish)。
*/
if (!(eflags & (EXEC_FLAG_SKIP_TRIGGERS | EXEC_FLAG_EXPLAIN_ONLY)))AfterTriggerBeginQuery();
/*
初始化计划状态树
*/
// 调用 InitPlan(queryDesc, eflags) 函数来初始化查询计划的状态树。
// 在执行查询之前,需要准备好执行计划所需的状态和数据结构,以便后续的执行操作。
InitPlan(queryDesc, eflags);
// 通过 MemoryContextSwitchTo(oldcontext) 切换回之前的内存上下文,将执行上下文切换回原始的内存上下文。
// 这是为了确保在初始化过程中使用的内存上下文不会影响后续的执行过程,避免内存泄漏或上下文混乱的问题。
MemoryContextSwitchTo(oldcontext);

这段代码用于初始化查询计划的状态树。并将上下文信息切换到oldcontext。

standard_ExecutorStart 函数的内容可以总结如下:

  1. 进行一些初始化工作,如创建执行状态结构 EState、设置执行标志 eflags、创建内存上下文等。
  2. 切换到执行上下文内存,并进行一些内存上下文的设置和切换。
  3. 基于传入的查询描述符 queryDesc 和执行标志 eflags,设置命令ID和触发器相关的上下文。
  4. 初始化查询计划的状态树,为执行做准备。
  5. 切换回之前的内存上下文,确保后续的执行过程不受初始化过程的影响。

http://www.ppmy.cn/news/490080.html

相关文章

国内技术网站逛腻了?国外程序员常浏览的 8 大网站,了解一下

每个行业都有自己的圈子,而程序员也有自己的圈子,他们有自己喜欢经常浏览的社区网站和博客站点,都知道国内技术网站有CSDN,博客园, 掘金,v2ex,知乎等等技术交流平台,那么你知道国外程序员经常逛…

强烈推荐7个国外图片资源网站

强烈推荐7个国外图片资源网站 不知道你找图时是否有过这种烦恼,找到一个配图时发现分辨率低,找到高清图时发现有水印,找到一张美图时发现烂大街,好不容易找到一张心仪的图片时发现要收费!而且很贵! 强烈推…

【Pytest实战】Pytest 如何生成优美的测试报告(allure-pytest)

😄作者简介: 小曾同学.com,一个致力于测试开发的博主⛽️,主要职责:测试开发、CI/CD 如果文章知识点有错误的地方,还请大家指正,让我们一起学习,一起进步。😊 座右铭:不想…

【亲测有效】微信图片已过期的恢复方法

方法一: 方法二:把过期图片(变成显示图片已过期的)收藏起来,从收藏里点进去就能看到你收藏的图片原来的样子

微信图片过期怎么办?如何查看微信过期图片?3步即可

微信图片过期怎么办?在微信还未出现的时候都是通过电话或者QQ联系的,但是现在微信的火爆大家有目共睹,如今的社交圈子已经离不开微信这个工具的存在了! 好了,回到主题,我们在微信聊天的过程中经常会有图片之…

session过期删除php,session过期怎么恢复?

如何防止session超时 众所周知,当用户登录网站后较长一段时间没有与服务器进行交互,将会导致服务器上的用户会话数据(即session)被销毁。此时,当用户再次操作网页时,如果服务器进行了session校验,那么浏览器将会提醒用…

重装系统后QQ聊天记录恢复方法

重装系统后QQ聊天记录恢复方法 近日重新安装了系统,重新安装了腾讯的、TM,TM也是安装在之前的目录底下,但是聊天记录和之前的自定义表情都不见了,看来没有自动恢复回来。 我这里还有一个特殊的情况,早前我用的是QQ…

微信过期视频怎么恢复?恢复视频的方法已经给你总结好了!

案例:微信视频过期,已经被清理怎么办? 【朋友之前发的视频过期了,现在怎么都找不到,有什么方法可以恢复回来吗?感谢!】 微信作为一款热门的社交应用程序,允许用户发送和接收照片、视…