在 PostgreSQL 中异常处理的主要代码包括 PG_TRY,PG_CATCH,PG_RE_THROW。
在 elog.h 代码中可以找到详细的描述:
/*---------- * API for catching ereport(ERROR) exits. Use these macros like so: * * PG_TRY(); * { * ... code that might throw ereport(ERROR) ... * } * PG_CATCH(); * { * ... error recovery code ... * } * PG_END_TRY(); * * (The braces are not actually necessary, but are recommended so that * pgindent will indent the construct nicely.) The error recovery code * can either do PG_RE_THROW to propagate the error outwards, or do a * (sub)transaction abort. Failure to do so may leave the system in an * inconsistent state for further processing. * * For the common case that the error recovery code and the cleanup in the * normal code path are identical, the following can be used instead: * * PG_TRY(); * { * ... code that might throw ereport(ERROR) ... * } * PG_FINALLY(); * { * ... cleanup code ... * } * PG_END_TRY(); * * The cleanup code will be run in either case, and any error will be rethrown * afterwards. * * You cannot use both PG_CATCH() and PG_FINALLY() in the same * PG_TRY()/PG_END_TRY() block. * * Note: while the system will correctly propagate any new ereport(ERROR) * occurring in the recovery section, there is a small limit on the number * of levels this will work for. It's best to keep the error recovery * section simple enough that it can't generate any new errors, at least * not before popping the error stack. * * Note: an ereport(FATAL) will not be caught by this construct; control will * exit straight through proc_exit(). Therefore, do NOT put any cleanup * of non-process-local resources into the error recovery section, at least * not without taking thought for what will happen during ereport(FATAL). * The PG_ENSURE_ERROR_CLEANUP macros provided by storage/ipc.h may be * helpful in such cases. * * Note: if a local variable of the function containing PG_TRY is modified * in the PG_TRY section and used in the PG_CATCH section, that variable * must be declared "volatile" for POSIX compliance. This is not mere * pedantry; we have seen bugs from compilers improperly optimizing code * away when such a variable was not marked. Beware that gcc's -Wclobbered * warnings are just about entirely useless for catching such oversights. *---------- */ #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)
复制
这其中几个关键宏共同作用,实现了类似于CPP的异常机制
#define PG_TRY() \ do { \ sigjmp_buf *save_exception_stack = PG_exception_stack; \ ErrorContextCallback *save_context_stack = error_context_stack; \ sigjmp_buf local_sigjmp_buf; \ 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_END_TRY() \ } \ PG_exception_stack = save_exception_stack; \ error_context_stack = save_context_stack; \ } while (0)
复制
在PG_TRY中, 可能会抛出(throw) ereport(ERROR) 按照往常的处理, 这部分就直接报错退出了, 但是在这种情形下由于利用 setjmp 设置了跳转上下文,所以在出现ERROR异常的时候会直接跳转到PG_CATCH那部分代码
ereport中的这个跳转是在 pg_re_throw 函数中利用 siglongjmp 来实现的
一般的erreport 和 elog 在 ERROR 级别下的机制:
观察 postgres.c 的这个地方(3868行):
if (sigsetjmp(local_sigjmp_buf, 1) != 0)
这说明当有异常的时候 PG 会跳转到这里, 相当于设置了一个savepoint 。
在 EmitErrorReport() 这个函数中会向 客户端发送异常或 报错
之后调用 AbortCurrentTransaction() 方法把当前的事务终止,之后重新进入事件循环
最后修改时间:2020-11-06 16:53:17
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。
评论
相关阅读
玩一玩系列——玩玩pg_mooncake(PostgreSQL的高性能列存新贵)
小满未满、
507次阅读
2025-03-03 17:18:03
王炸!OGG 23ai 终于支持从PostgreSQL备库抽取数据了
曹海峰
385次阅读
2025-03-09 12:54:06
玩一玩系列——玩玩login_hook(一款即将停止维护的PostgreSQL登录插件)
小满未满、
369次阅读
2025-03-08 18:19:28
明明想执行的SQL是DELETE、UPDATE,但为什么看到的是SELECT(FDW的实现原理解析)
小满未满、
343次阅读
2025-03-19 23:11:26
PostgreSQL初/中/高级认证考试(3.15)通过考生公示
开源软件联盟PostgreSQL分会
292次阅读
2025-03-20 09:50:36
IvorySQL 4.4 发布 - 基于 PostgreSQL 17.4,增强平台支持
通讯员
180次阅读
2025-03-20 15:31:04
套壳论
梧桐
175次阅读
2025-03-09 10:58:17
命名不规范,事后泪两行
xiongcc
164次阅读
2025-03-13 14:26:08
版本发布| IvorySQL 4.4 发布
IvorySQL开源数据库社区
108次阅读
2025-03-13 09:52:33
宝藏PEV,助力你成为SQL优化高手
xiongcc
98次阅读
2025-03-09 23:34:23