Postgresql源码(118)elog/ereport报错跳转功能分析
1 日志接口
elog.c完成PG中日志的生产、记录工作,对外常用接口如下:
1.1 最常用的ereport和elog
ereport(ERROR,(errcode(ERRCODE_UNDEFINED_TABLE),errmsg("relation \"%s\" does not exist",relation->relname)));
elog(ERROR, "unexpected enrtype: %d", enrmd->enrtype);
其实都是在调用errstart和errfinish函数完成具体工作。
#define elog(elevel, ...) \ereport(elevel, errmsg_internal(__VA_ARGS__))#define ereport(elevel, ...) \ereport_domain(elevel, TEXTDOMAIN, __VA_ARGS__)#define ereport_domain(elevel, domain, ...) \do { \pg_prevent_errno_in_scope(); \if (__builtin_constant_p(elevel) && (elevel) >= ERROR ? \errstart_cold(elevel, domain) : \errstart(elevel, domain)) \__VA_ARGS__, errfinish(__FILE__, __LINE__, __func__); \if (__builtin_constant_p(elevel) && (elevel) >= ERROR) \pg_unreachable(); \} while(0)
2 日志数据结构
- 单条日志被抽象为ErrorData,记录了日志的全部信息。
- elog.c提供了一个深度为5的stack来存放最多五层的ErrorData,大部分场景下,stack只会使用一层:
#define ERRORDATA_STACK_SIZE 5
static ErrorData errordata[ERRORDATA_STACK_SIZE];

3 日志的工作流程
每一条日志都是经过errstart和errfinish函数处理的,分工大致为:
- errstart
- 在errdata堆栈中压入一个新的edata
- 为edata填充部分错误信息,例如错误等级、需要输出到server/client、按需升级错误等级(例如Crit区域中大于等于ERROR的需要变成PINIC)
- errfinish
- 在进入errfinish前,错误信息的文本经过errmsg或errmsg_internal函数中的EVALUATE_MESSAGE宏记入edata中的message中,内存用的是errfinish
- 三部分工作:
- 3.1 完成PG_TRY()、PG_CATCH()跳转功能,为errfinish添加try/catch功能
- 3.2 完成error_context_stack的回调功能,为errfinish增加报错信息
- 3.3 完成EmitErrorReport,为errfinish发送错误信息
3.1 完成PG_TRY()、PG_CATCH()跳转功能,为errfinish添加try/catch功能
注意PG_CATCH和PG_FINALLY是二选一的,区别是PG_FINALLY会在最后把异常重新抛出去,而PG_CATCH自己处理完了就不在向上抛了。
#define PG_TRY() \do { \sigjmp_buf *_save_exception_stack = PG_exception_stack; \ErrorContextCallback *_save_context_stack = error_context_stack; \sigjmp_buf _local_sigjmp_buf; \bool _do_rethrow = false; \if (sigsetjmp(_local_sigjmp_buf, 0) == 0) \{ \PG_exception_stack = &_local_sigjmp_buf#define PG_CATCH(...) \} \else \{ \PG_exception_stack = _save_exception_stack; \error_context_stack = _save_context_stack#define PG_FINALLY() \} \else \_do_rethrow = true; \{ \PG_exception_stack = _save_exception_stack; \error_context_stack = _save_context_stack#define PG_END_TRY() \} \if (_do_rethrow) \PG_RE_THROW(); \PG_exception_stack = _save_exception_stack; \error_context_stack = _save_context_stack; \} while (0)
我们先看一个PG中常规的报错流程,注意是不在PG_TRY中的elog(ERROR),发生>=ERROR级别的异常后,在errfinish中会抛出异常,jmp到PostgresMain函数中的sigsetjmp的位置,进入异常回收流程。

那么如果代码中的报错被PG_TRY、PG_CATCH包裹时,抛出异常会发生什么呢?

3.2 完成error_context_stack的回调功能,为errfinish增加报错信息
error_context_stack是一个Lisrt记录了回调函数回调函数的参数,这里的函数的作用是添加报错信息,因为这些函数会在errfinish时被调用,函数中往往都会使用errcontext_msg记录一些更详细的报错文本。
typedef struct ErrorContextCallback
{struct ErrorContextCallback *previous;void (*callback) (void *arg);void *arg;
} ErrorContextCallback;extern PGDLLIMPORT ErrorContextCallback *error_context_stack;
例如pl编译时配置的plpgsql_compile_error_callback函数,为了增加编译报错时,错误的发生的位置等:
do_compile...plerrcontext.callback = plpgsql_compile_error_callback;plerrcontext.arg = forValidator ? proc_source : NULL;plerrcontext.previous = error_context_stack;error_context_stack = &plerrcontext;...
static void
plpgsql_compile_error_callback(void *arg)
{if (arg){/** Try to convert syntax error position to reference text of original* CREATE FUNCTION or DO command.*/if (function_parse_error_transpose((const char *) arg))return;/** Done if a syntax error position was reported; otherwise we have to* fall back to a "near line N" report.*/}if (plpgsql_error_funcname)errcontext("compilation of PL/pgSQL function \"%s\" near line %d",plpgsql_error_funcname, plpgsql_latest_lineno());
}
error_context_stack和上面提到的PG_exception_stack都会在TRY中进行保存和恢复,为什么:
- PG_exception_stack比较好理解,因为TRY时会建一个新的jmpbuf用PG_exception_stack指向,之前的旧值需要记录下来,TRY完了需要恢复。
- error_context_stack的回调函数是在子模块中配置的,正常执行完子模块会把error_context_stack恢复原样,但一旦error发生了跳转,恢复逻辑就被跳过了。所以在TRY中自带了恢复error_context_stack的逻辑。
3.3 完成EmitErrorReport,为errfinish发送错误信息
errfinish......EmitErrorReport......
EmitErrorReport函数中会执行发送逻辑:
EmitErrorReport...if (edata->output_to_server && emit_log_hook)(*emit_log_hook) (edata);/* Send to server log, if enabled */if (edata->output_to_server)send_message_to_server_log(edata); // 写 write_syslog/* Send to client, if enabled */if (edata->output_to_client)send_message_to_frontend(edata); // 写libpq,发送到客户端或主进程
4 CopyErrorData / FlushErrorState / FreeErrorData
由于edata中的信息是在ErrorContext中申请的,在PG_CATCH时,是能拿到edata使用的,但在catch时不应该使用ErrorContext申请任何内存,所以惯用法是在PG_CATCH中用CopyErrorData把edata拷贝到当前的上下文中,在进行操作。然后把ErrorContext中的edata用FlushErrorState清理干净。
例如PL中的用法
PG_CATCH();{ErrorData *edata;....../* Save error info in our stmt_mcontext */MemoryContextSwitchTo(stmt_mcontext);// 拷贝edata到当前上下文中edata = CopyErrorData();// ErrorContext中的用完尽快释放FlushErrorState();......// 尽情使用使用edataexception_matches_conditions(edata, exception->conditions)......
相关文章:
Postgresql源码(118)elog/ereport报错跳转功能分析
1 日志接口 elog.c完成PG中日志的生产、记录工作,对外常用接口如下: 1.1 最常用的ereport和elog ereport(ERROR,(errcode(ERRCODE_UNDEFINED_TABLE),errmsg("relation \"%s\" does not exist",relation->relname)));elog(ERRO…...
Python Selenium中的强大等待设置详解
更多资料获取 📚 个人网站:ipengtao.com 在Web自动化测试中,等待是至关重要的一环,而Selenium提供了丰富的等待设置来确保测试脚本的可靠性和稳定性。本文将深入研究Python Selenium中常用的必备等待设置,包括显式等待…...
ACL实现固定时间访问资源——项目
文章目录 一、前言二、项目拓扑三、项目需求四、配置思路五、配置步骤1 IP地址2 端口类型3 静态路由4 流策略 六、结语 免责声明 本文旨在提供信息和解决问题的建议,观点和建议可能不适用于个人情况,仅供参考!!! 文章中…...
前端学习——关于前端框架的思考
前端框架 我们知道在AngularJS,react,vue等前端框架出现之前,前端开发都是通过js直接操作dom树来实现的,而有了前端框架之后,前端开发基本上不需要在直接操作dom树,相当于在原生html的dom树之间和前端程序…...
大创项目推荐 深度学习+opencv+python实现车道线检测 - 自动驾驶
文章目录 0 前言1 课题背景2 实现效果3 卷积神经网络3.1卷积层3.2 池化层3.3 激活函数:3.4 全连接层3.5 使用tensorflow中keras模块实现卷积神经网络 4 YOLOV56 数据集处理7 模型训练8 最后 0 前言 🔥 优质竞赛项目系列,今天要分享的是 &am…...
Linux(二)常用命令
文章目录 一、文件管理命令1.1 chmod1.2 chown1.3 cat1.4 cp1.5 find1.6 head1.7 tail1.8 less1.9 more1.10 mv1.11 rm1.12 touch1.13 vim1.14 >和>>1.15 scp1.16 ln1.17 怎么用命令查看日志 二、文档管理命令2.1 grep2.2 wc2.3 echo 三、磁盘管理命令3.1 cd3.2 df3.3…...
PHP通过mailer发送邮箱
<?php namespace sw\controler\action;require(APP_DIR./extend/PHPMailer/class.phpmailer.php); require(APP_DIR./extend/PHPMailer/class.smtp.php); class action_test_mailer extends Base {public function test(){$smtpemailto"1967899707qq.com";//接收…...
c# OpenCV 基本绘画(直线、椭圆、矩形、圆、多边形、文本)(四)
我们将在这里演示如何使用几何形状和文本注释图像。 Cv2.Line() 绘制直线 Cv2.Ellipse() 绘制椭圆Cv2.Rectangle() 绘制矩形Cv2.Circle() 绘制圆Cv2.FillPoly() 绘制多边形Cv2.PutText() 绘制文本 一、绘制直线 Cv2.Line(image, start_point, end_point, color, thickness) …...
js键盘事件keydown事件,防止重复触发,组合键的配合使用
js键盘事件keydown事件,防止重复触发 键盘事件类型主要有三种: keydown 、keypress(不建议使用,部分浏览器已放弃)和 keyup 。 添加普通键盘keydown事件 // 监听键盘按下事件document.addEventListener(keydown, function(event) {// 输出按…...
【Docker】升级docker或者docker到docker-ce完全保留镜像和容器,不影响原容器使用方法
升级docker或者docker到docker-ce完全保留镜像和容器,不影响原容器使用方法 一、介绍二、升级方法 三、遇到问题说明 以下是我的使用场景,docker升级到docker-ce,但对于docker-ce升级也通用!亲测! 一、介绍 CentOS自带…...
22 3GPP在SHF频段基于中继的5G高速列车场景中的标准化
文章目录 信道模型实验μ参考信号初始接入方法波形比较 RRH:remote radio head 远程无线头 HTS:high speed train 高速移动列车 信道模型 考虑搭配RRH和车载中继站之间的LOS路径以及各种环境(开放或峡谷),在本次实验场…...
C语言之初识C语言
文章目录 前言一、什么是C语言二、第一个C语言程序三、数据类型四、变量,常量1、变量1.1 变量的命名1.2 变量的分类1.3 变量的使用1.4 变量的作用域和生命周期2、变量 五、字符串1. 概念2. 求解字符串的长度【strlen】3. 转义字符【含笔试题】 六、注释七、选择语句…...
Modbus-TCP数据帧
Modbus-TCP基于4种报文类型 MODBUS 请求是客户机在网络上发送用来启动事务处理的报文MODBUS 指示是服务端接收的请求报文MODBUS 响应是服务器发送的响应信息MODBUS 证实是在客户端接收的响应信息 Modbus-TCP报文: 报文头MBAP MBAP为报文头,长度为7字节,…...
linux搭建gitlab
gitlab的介绍 区别于github,github是面向互联网基于git实现的代码托管平台,gitlab是基于Ruby语言实现的git管理平台软件,一般用于公司内部代码仓库。 gitlab组成 Nginx 静态Web服务器Gitlab-workhorse 轻量级的反向代理服务器Gitlab-shell 用…...
GEM5 Garent CPU cache消息传递路径:1. NI部分
简介 我们仔细分析下图怎么连的,以及消息传递路径。 图来自https://www.gem5.org/documentation/general_docs/ruby/ 代码的连接 fs.py->ruby.py-> gem5/configs/ruby/MESI_Two_Level.py 中的 create_system( options, full_system, system, dma_ports, b…...
Java设计模式之单例模式以及如何防止通过反射破坏单例模式
单例模式 单例模式使用场景 什么是单例模式?保障一个类只能有一个对象(实例)的代码开发模式就叫单例模式 什么时候使用? 工具类!(一种做法,所有的方法都是static,还有一种单…...
python flask+vue实现前后端图片上传
python flaskvue实现前后端图片上传 vue代码如下: <template><div><input type"file" change"handleFileChange"/><button click"uploadFile">上传</button><br><img :src"imageUrl&…...
centos7安装开源日志系统graylog5.1.2
安装包链接:链接:https://pan.baidu.com/s/1Zl5s7x1zMWpuKfaePy0gPg?pwd1eup 提取码:1eup 这里采用的shell脚本安装,脚本如下: 先使用命令产生2个参数代入到脚本中: 使用pwgen生成password_secret密码 …...
5G+云渲染技术:将如何快速推进XR和元宇宙?
XR(扩展现实)领域正在以惊人的速度增长。目前,到 2024 年,一些专家表示这个行业的价值将达到 3000 亿美元。 这个行业发展如此迅速的部分原因是 XR 将在商业环境中的带来巨大利益。近年来,很多企业遇到了将增强现实和…...
【leetcode234】回文链表Java代码讲解
12.21 234. 回文链表 给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。 示例 1: 输入:head [1,2,2,1] 输出:true示例 2: 输入&a…...
储能系统中的双向DCDC变流器:模型预测控制下的高效稳定运行策略
储能双向DCDC变流器-模型预测控制 储能buck-boost双向dcdc负载 [1]初级控制为下垂控制 [2]电压环才采用PI控制 [3]电流环采用模型预测 ①蓄电池控制外环使用U-I下垂控制PI控制器产生电流环给定值 ②设计了电流内环的模型预测控制器,模型预测控制由于是主动的预测&am…...
基于设备树与内核中断的125KHZ RFID曼彻斯特码实时解码实践
1. 曼彻斯特码解码原理详解 125KHz RFID系统广泛用于门禁、物流追踪等场景,其数据传输采用曼彻斯特编码方式。这种编码最大的特点是每个数据位都包含电平跳变,使得时钟恢复变得简单。具体来说,EM4100卡片每传送一位数据需要64个载波周期&…...
vLLM-v0.17.1效果展示:vLLM 0.17.1对Long Context(256K)支持验证
vLLM-v0.17.1效果展示:vLLM 0.17.1对Long Context(256K)支持验证 1. vLLM框架核心能力概览 vLLM是一个专为大型语言模型(LLM)设计的高性能推理和服务库,最初由加州大学伯克利分校的天空计算实验室开发,现已发展为社区…...
如何通过自动化工具高效获取阴阳师游戏资源?完整实践指南
如何通过自动化工具高效获取阴阳师游戏资源?完整实践指南 【免费下载链接】OnmyojiAutoScript Onmyoji Auto Script | 阴阳师脚本 项目地址: https://gitcode.com/gh_mirrors/on/OnmyojiAutoScript 阴阳师自动化工具是一款功能强大的智能辅助应用,…...
OpenClaw会议纪要大师:Qwen3-32B实时转录飞书语音会议
OpenClaw会议纪要大师:Qwen3-32B实时转录飞书语音会议 1. 为什么需要自动化会议纪要 每次开完会最头疼的就是整理会议纪要。作为团队的技术负责人,我每周要参加至少8场跨部门会议,传统的手动记录方式让我苦不堪言——要么记录不全重点&…...
从预处理指令看跨语言兼容:手把手封装C++库供C调用的5个关键步骤
从预处理指令看跨语言兼容:手把手封装C库供C调用的5个关键步骤 在嵌入式开发和SDK设计中,经常需要将C库封装成C语言接口。这种跨语言调用看似简单,实则暗藏玄机。本文将深入剖析extern "C"和__cplusplus预处理指令的底层原理&#…...
FigmaCN:5分钟快速实现Figma中文界面的终极解决方案
FigmaCN:5分钟快速实现Figma中文界面的终极解决方案 【免费下载链接】figmaCN 中文 Figma 插件,设计师人工翻译校验 项目地址: https://gitcode.com/gh_mirrors/fi/figmaCN 还在为Figma英文界面而烦恼吗?figmaCN是一款专为中文用户打造…...
Docker 部署 Vaultwarden:轻量级自托管密码管理解决方案
1. 为什么选择Vaultwarden作为自托管密码管理方案 在这个数字时代,我们每个人平均要管理超过100个在线账户的密码。传统的密码管理方式——用同一个简单密码注册所有网站,或者把密码写在记事本上——已经远远不能满足安全需求。这就是为什么像Bitwarden这…...
致开发者:别再重复造轮子,这个开源商城系统让你把时间花在刀刃上
作为开发者,你是否厌倦了每次新项目都要从零搭建电商后台?商品、订单、会员、营销……这些基础模块耗费了你多少宝贵的创造力?今天,我们想和你聊聊一个能让你“拿来即用,改也不难”的解决方案——CRMEB开源商城系统。它…...
S2-Pro提示词(Prompt)工程入门:从零到一掌握高效对话技巧
S2-Pro提示词(Prompt)工程入门:从零到一掌握高效对话技巧 1. 为什么需要学习提示词工程 你可能已经发现,同样的AI模型,在不同人手里表现天差地别。有人能让它写出专业报告,有人却只能得到敷衍的回复。这中…...
