Postgresql源码(103)PLpg/SQL中的表达式ExprContext
创始人
2025-06-01 00:52:26
0

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中,存在大量语法需要调用主解析器进行计算,例如:

CREATE or replace function tp14_outter(a in integer , b out integer,c out integer)
RETURNS int
LANGUAGE plpgsql
AS $$
DECLARErr int;b int;c int;
BEGINb := 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。

上一篇:运维经典面试题

下一篇:跨域问题解决

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
美团联名卡审核成功待激活(美团... 今天百科达人给各位分享美团联名卡审核成功待激活的知识,其中也会对美团联名卡审核未通过进行解释,如果能...
一帆风顺二龙腾飞三阳开泰祝福语... 本篇文章极速百科给大家谈谈一帆风顺二龙腾飞三阳开泰祝福语,以及一帆风顺二龙腾飞三阳开泰祝福语结婚对应...