Postgresql源码(103)PLpg/SQL中的表达式ExprContext

news/2024/7/9 22:50:46 标签: sql, postgresql, 数据库, expr

0 总结

(可以最后看)

  1. PLpgSQL_execstate中包含的两个结构:EState *simple_eval_estateExprContext *eval_econtext
  2. 丢给SQL引擎执行时一般需要ExprContext就够了,但是ExprContext会依赖EState结构才能创建出来,所以PL在执行时,plpgsql_exec_function函数需要传入EState结构,方便后面ExprContext的创建。
  3. PL中使用的ExprContext,创建后,会自动压入simple_econtext_stack堆栈。因为PL中的异常处理会自动启动子事务,为了让表达式计算申请的资源能和子事务一块释放(避免污染顶层事务的ExprContext),需要将ExprContext与子事务关联起来:
    • 所以如果没有发生异常,那么eval_econtext会跟着ReleaseCurrentSubTransaction在子事务提交中释放。
    • 如果发生异常了,那么eval_econtext会跟着RollbackAndReleaseCurrentSubTransaction在子事务回滚中释放。

1 PL运行时信息:PLpgSQL_execstate

PostgreSQL的PLpg/SQL中任何语句的运行,都需要记录运行时的状态信息。在SQL层的执行器中运行时状态使用EState记录,在PL中状态信息使用PLpgSQL_execstate结构记录。

/*
 * Runtime execution data
 */
typedef struct PLpgSQL_execstate
{
	PLpgSQL_function *func;		/* function being executed */
    ...
	Datum		retval;
	bool		retisnull;
	Oid			rettype;		    // 返回值处理
    ...
	Oid			fn_rettype;		
	bool		retistuple;
	bool		retisset;

	bool		readonly_func;
	bool		atomic;             // 函数是原子的,过程是非原子的,非原子的能执行commit/rollback
                                    // return next of 缓存
	Tuplestorestate *tuple_store;
	TupleDesc	tuple_store_desc;
	...
	int			ndatums;            // 变量数组个数
	PLpgSQL_datum **datums;         // 变量数组
    ...
	
	
	EState	   *simple_eval_estate;     // 为什么这里需要有EState?
	ResourceOwner simple_eval_resowner;
    ...
	SPITupleTable *eval_tuptable;
	uint64		eval_processed;
	ExprContext *eval_econtext;         // 为什么这里需要有ExprContext?

    ...
} PLpgSQL_execstate;

在上述PLpgSQL_execstate结构中,为什么会出现EState呢,simple_eval_estate的作用是什么?

答案:表达式计算。

2 PL表达式计算

在PL中,存在大量语法需要调用主解析器进行计算,例如:

sql">CREATE or replace function tp14_outter(
  a in integer , 
  b out integer,
  c out integer)
RETURNS int
LANGUAGE plpgsql
AS $$
DECLARE
  rr int;
  b int;
  c int;
BEGIN
  b := 1 + 1;
  c := b / 2;
  rr := b + c + other_func(1,2,3);
  return rr;
END;
$$;

目前PL引擎会把assign语句的右值封装成字符串的形式保存下来,等到运行时会发送给SQL引擎计算结果。

例如上面的c := b / 2

  1. 在PL编译后,会记录字符串select b / 2
  2. 在PL运行时,会调用SQL引擎,将字符串select b / 2通过SPI发过去,走一遍完成的语法、语义分析,优化器,执行器(表达式计算模块),最终拿到结果。(主解析器应该不认识b,怎么计算呢?答案:回调钩子函数拿值)。

那么调用SQL引擎的表达式计算模块,一定需要SQL引擎的运行时结构EState。

所以PLpgSQL_execstate中会包含EState *simple_eval_estate;ExprContext *eval_econtext;结构。

3 PL表达式运行时内存结构ExprContext

PLpgSQL_execstate中包含的两个结构:

  • EState *simple_eval_estate
  • ExprContext *eval_econtext

实际上呢,丢给SQL引擎执行时一般需要ExprContext就够了,但是ExprContext会依赖EState结构才能创建出来,所以PL在执行时,plpgsql_exec_function函数需要传入EState结构,方便后面ExprContext的创建。

  • PL中的函数会使用共享的EState结构用于创建ExprContext:shared_simple_eval_estate
  • PL中的匿名块会使用私有的EState结构用于创建ExprContext

在这里插入图片描述
PL中使用的ExprContext,创建后,会自动压入simple_econtext_stack堆栈,为什么呢?

因为PL中的异常处理会自动启动子事务,为了让表达式计算申请的资源能和子事务一块释放,需要将ExprContext与子事务关联起来:
在这里插入图片描述
一旦子事务释放,在回调函数plpgsql_subxact_cb中,会释放simple_econtext_stack堆栈中所有和该子事务相关的ExprContext。

void
plpgsql_subxact_cb(SubXactEvent event, SubTransactionId mySubid,
				   SubTransactionId parentSubid, void *arg)
{
	if (event == SUBXACT_EVENT_COMMIT_SUB || event == SUBXACT_EVENT_ABORT_SUB)
	{
		while (simple_econtext_stack != NULL &&
			   simple_econtext_stack->xact_subxid == mySubid)
		{
			SimpleEcontextStackEntry *next;

			FreeExprContext(simple_econtext_stack->stack_econtext,
							(event == SUBXACT_EVENT_COMMIT_SUB));
			next = simple_econtext_stack->next;
			pfree(simple_econtext_stack);
			simple_econtext_stack = next;
		}
	}
}

所以如果没有发生异常,那么eval_econtext会跟着ReleaseCurrentSubTransaction在子事务提交中释放。

if (block->exceptions)
    ExprContext *old_eval_econtext = estate->eval_econtext;
    BeginInternalSubTransaction(NULL);
    PG_TRY();
    {
        plpgsql_create_econtext(estate);
        rc = exec_stmts(estate, block->body);
        ReleaseCurrentSubTransaction();     <<<<<<--------
        estate->eval_econtext = old_eval_econtext;
    }

如果发生异常了,那么eval_econtext会跟着RollbackAndReleaseCurrentSubTransaction在子事务回滚中释放。

if (block->exceptions)
    ExprContext *old_eval_econtext = estate->eval_econtext;
    BeginInternalSubTransaction(NULL);
    PG_TRY();
    {
        plpgsql_create_econtext(estate);
        rc = exec_stmts(estate, block->body);
        ReleaseCurrentSubTransaction();     <<<<<<--------
        estate->eval_econtext = old_eval_econtext;
    }
    PG_CATCH();
    {
        RollbackAndReleaseCurrentSubTransaction();
        estate->eval_econtext = old_eval_econtext;
    }

4 相关全局变量、函数

typedef struct SimpleEcontextStackEntry
{
	ExprContext *stack_econtext;	/* a stacked econtext */
	SubTransactionId xact_subxid;	/* ID for current subxact */
	struct SimpleEcontextStackEntry *next;	/* next stack entry up */
} SimpleEcontextStackEntry;

static EState *shared_simple_eval_estate = NULL;
static SimpleEcontextStackEntry *simple_econtext_stack = NULL;

全局变量:

  • simple_econtext_stack:ExprContext堆栈,每个元素对应一个子事务,需要再子事务创建后主动申请出来,子事务释放后会跟随子事务清理被释放。
  • shared_simple_eval_estate:ExprContext依赖的EState结构,SQL引擎的运行时结构非常重要,在PL中主要用于创建ExprContext。

函数:

  • plpgsql_create_econtext
    • 用于创建ExprContext结构,会主动使用EState(shared_simple_eval_estate)。
    • 内部使用CreateExprContext创建ExprContext。
  • plpgsql_estate_setup
    • 用于创建PL的运行时结构PLpgSQL_execstate
    • 会主动使用EState(shared_simple_eval_estate)。
    • 会调用plpgsql_create_econtext创建ExprContext。

http://www.niftyadmin.cn/n/171053.html

相关文章

辉煌优配|危机即转机?摩根士丹利预计美股即将迎来熊市尾声

摩根士丹利策略师表明&#xff0c;银行体系遭受压力意味着美股行将迎来熊市尾声&#xff0c;但这个完毕的过程或许十分苦楚。 该投行首席美国股票策略师威尔逊&#xff08;Michael Wilson&#xff09;周一在分析师报告中写到&#xff0c;美国股市正处于退出熊市的前期苦楚阶段。…

Vue项目预渲染

前言 Ajax 技术的出现&#xff0c;让我们的 Web 应用能够在不刷新的状态下显示不同页面的内容&#xff0c;这就是单页应用。在一个单页应用中&#xff0c;往往只有一个 html 文件&#xff0c;然后根据访问的 url 来匹配对应的路由脚本&#xff0c;动态地渲染页面内容。单页应用…

SpringBoot 实战——统⼀⽤户登录权限验证

文章目录 用户登录权限效验1.1 最初的用户登录验证1.2 Spring AOP 用户统一登录验证的问题1.3 Spring 拦截器1.3.1 准备工作1.3.2 自定义拦截器1.3.3 将自定义拦截器加入到系统配置1.4 拦截器实现原理1.4.1 实现原理源码分析1.4.2 拦截器小结1.5 扩展:统一访问前缀添加用户登录…

[数据分析实战][37] 基于pandasql和plotly的数据科学家薪资分析与可视化 @ShowMeAI

参考资料&#xff1a; 数据科学家赚多少&#xff1f;数据全分析与可视化-ShowMeAI 前言 代码实际跑过一遍&#xff0c;原文中有一些错误&#xff0c;都已经修改过来了。大多数修改的地方都用“修改”标注了。要查看相应内容建议使用搜索“修改”查看。 Table of Contents 1…

基于springboot+mysql+jsp实现健身房管理系统

基于springbootmysqljsp实现健身房管理系统一、系统介绍1、系统主要功能&#xff1a;2.涉及技术框架&#xff1a;3.本项目所用环境&#xff1a;二、功能展示三、其它系统四、获取源码一、系统介绍 1、系统主要功能&#xff1a; 管理员登录模块 会员管理模块 教练管理模块 课程…

jpg格式图片打不开怎么办

jpg图片是我们很常见的图片格式&#xff0c;打开方法也很简单&#xff0c;只要点击即可打开。当然也会遇到有点开后&#xff0c;却无法打开的图片。虽然比较少但还是会遇到&#xff0c;那么当我们遇到jpg格式图片打不开怎么办呢?您可以通过下面的详细教程来快速图片打不开的图…

源代码安全管理的经验分享

数据保密产品发展至今大致可分为两类&#xff1a;文档加密类产品和沙盒类&#xff08;或者称为环境加密&#xff09;产品。两类产品设计理念和功能迥异。从这几年的应用情况看&#xff0c;数据防泄密项目想要实施成功&#xff0c;除了选择合适自身的产品外&#xff0c;更加需要…

德国空派专线 什么是德国空派专线物流

一、什么是德国空派专线物流 德国空派专线物流是指货物通过空运渠道运输到德国&#xff0c;空派是空运配送&#xff0c;通关后由当地物流或快递配送至海外仓&#xff0c;然后根据需求派送至亚马逊仓库&#xff0c;亚马逊仓库不需要预约&#xff0c;所以仓库效率会很好&#xff…