PgSQL技术内幕 - ereport ERROR跳转机制

PgSQL技术内幕 - ereport ERROR跳转机制

使用客户端执行SQL的时候经常遇到报ERROR错误,然后SQL语句就退出了。当然,事务也会回滚掉。本文我们看下它是如何做到退出SQL语句并回滚事务的。

1、以insert一个numeric类型值为例

表一个字段为numeric(10,2)类型,表示存储10位数字,精确到小数点后两位。当插入的值超过10位时就会报错:numeric field overflow

首先观察报错的位置:

PgSQL技术内幕 - ereport ERROR跳转机制_第1张图片

由ereport输出打印日志。从函数ereport_domain函数的调用逻辑,如下图所示,可以看到通过siglongjmp函数进行跳转。

PgSQL技术内幕 - ereport ERROR跳转机制_第2张图片

2、PG_TRY/PG_CATCH/PG_RE_THROW/PG_END_TRY

从上面可知,PG中通过PG_RE_THROW完成跳转,捕获ereport(ERROR)的API为:

PG_TRY();
{
  ... code that might throw ereport(ERROR) ...
}
PG_CATCH();
{
  ... error recovery code ...
}
PG_END_TRY();

该宏定义:

PgSQL技术内幕 - ereport ERROR跳转机制_第3张图片

sigsetjmp会保存目前堆栈环境,然后将目前的地址作为一个记号。程序其他地方调用siglongjmp时会直接跳到这个记号位置,然后还原堆栈,继续程序的执行。

3、整体逻辑

PgSQL技术内幕 - ereport ERROR跳转机制_第4张图片

从PostgresMain接收命令ReadCommand到调用exec_simple_query执行SQL,然后standard_ExectorRun执行器开始执行;再到ExecModifyTable执行insert操作。首先,从子节点获取slot,然后执行ExecInsert执行插入操作。红色箭头为插入操作函数调用方向。

从子节点获取slot时,会调用apply_typmod函数校验numeric类型值是否会溢出。一旦溢出则报ereport ERROR。

蓝色箭头为跳转方向。从apply_typmod函数跳转到standard_ExecutorRun的PG_TRY位置,然后通过PG_CATCH处理一些清理操作,再由PG_RE_THROW跳转到exec_simple_query的PG_TRY位置,同理一直跳转到PostgresMain的sigsetjmp位置。

由此完成插入过程中报错退出动作,也就是说当ereport报ERROR时,并不是继续当前函数的退出逻辑,而是跳转到PostgresMain的sigsetjmp位置接着执行,继续一些清理操作,包括调用AbortCurrentTransaction回滚事务。

从上图中可以看到,回滚事务后会接着再次进入for循环,调用ReadCommand读取新命令执行,当然若没有命令到来,则进入等待。

你可能感兴趣的:(PgSQL技术内幕 - ereport ERROR跳转机制)