mirror of
https://github.com/postgres/postgres.git
synced 2025-07-26 01:22:12 +03:00
PG_FINALLY
This gives an alternative way of catching exceptions, for the common case where the cleanup code is the same in the error and non-error cases. So instead of PG_TRY(); { ... code that might throw ereport(ERROR) ... } PG_CATCH(); { cleanup(); PG_RE_THROW(); } PG_END_TRY(); cleanup(); one can write PG_TRY(); { ... code that might throw ereport(ERROR) ... } PG_FINALLY(); { cleanup(); } PG_END_TRY(); Discussion: https://www.postgresql.org/message-id/flat/95a822c3-728b-af0e-d7e5-71890507ae0c%402ndquadrant.com
This commit is contained in:
@ -277,6 +277,25 @@ extern PGDLLIMPORT ErrorContextCallback *error_context_stack;
|
||||
* (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
|
||||
@ -300,24 +319,33 @@ extern PGDLLIMPORT ErrorContextCallback *error_context_stack;
|
||||
*/
|
||||
#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) \
|
||||
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
|
||||
PG_exception_stack = &_local_sigjmp_buf
|
||||
|
||||
#define PG_CATCH() \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
PG_exception_stack = save_exception_stack; \
|
||||
error_context_stack = save_context_stack
|
||||
PG_exception_stack = _save_exception_stack; \
|
||||
error_context_stack = _save_context_stack
|
||||
|
||||
#define PG_FINALLY() \
|
||||
} \
|
||||
else \
|
||||
_do_rethrow = true; \
|
||||
{
|
||||
|
||||
#define PG_END_TRY() \
|
||||
} \
|
||||
PG_exception_stack = save_exception_stack; \
|
||||
error_context_stack = save_context_stack; \
|
||||
PG_exception_stack = _save_exception_stack; \
|
||||
error_context_stack = _save_context_stack; \
|
||||
if (_do_rethrow) \
|
||||
PG_RE_THROW(); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
|
Reference in New Issue
Block a user