This is a common pattern:
PG_TRY();
{
... code that might throw ereport(ERROR) ...
}
PG_CATCH();
{
cleanup();
PG_RE_THROW();
}
PG_END_TRY();
cleanup(); /* the same as above */
I've played with a way to express this more compactly:
PG_TRY();
{
... code that might throw ereport(ERROR) ...
}
PG_FINALLY({
cleanup();
});
See attached patch for how this works out in practice.
Thoughts? Other ideas?
One problem is that this currently makes pgindent crash. That's
probably worth fixing anyway. Or perhaps find a way to write this
differently.
--
Peter Eisentraut http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
From e4d05fba0b2e97f7344c77b17a3b8aa6378ded8f Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <[email protected]>
Date: Thu, 13 Dec 2018 11:19:07 +0100
Subject: [PATCH] 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();
});
---
contrib/auto_explain/auto_explain.c | 16 ++-----
contrib/dblink/dblink.c | 31 +++-----------
contrib/hstore_plpython/hstore_plpython.c | 8 +---
.../pg_stat_statements/pg_stat_statements.c | 24 +++--------
contrib/pg_trgm/trgm_regexp.c | 9 +---
contrib/postgres_fdw/connection.c | 9 +---
contrib/sepgsql/hooks.c | 8 +---
contrib/sepgsql/label.c | 42 +++++--------------
contrib/sepgsql/selinux.c | 8 +---
contrib/sepgsql/uavc.c | 9 +---
src/backend/catalog/index.c | 16 ++-----
src/backend/commands/async.c | 18 +-------
src/backend/commands/copy.c | 8 +---
src/backend/commands/event_trigger.c | 18 ++------
src/backend/commands/extension.c | 10 +----
src/backend/commands/matview.c | 8 +---
src/backend/commands/subscriptioncmds.c | 21 ++--------
src/backend/commands/trigger.c | 8 +---
src/backend/commands/vacuum.c | 10 +----
src/backend/libpq/be-fsstubs.c | 8 +---
src/backend/tcop/utility.c | 18 ++------
src/backend/utils/adt/xml.c | 25 +++--------
src/include/utils/elog.h | 30 +++++++++++++
src/pl/plperl/plperl.c | 24 ++---------
src/pl/plpgsql/src/pl_handler.c | 13 ++----
src/pl/plpython/plpy_cursorobject.c | 8 +---
src/pl/plpython/plpy_elog.c | 16 +------
src/pl/plpython/plpy_exec.c | 20 ++-------
src/pl/plpython/plpy_spi.c | 7 +---
src/pl/plpython/plpy_typeio.c | 8 +---
src/pl/tcl/pltcl.c | 17 ++------
31 files changed, 126 insertions(+), 349 deletions(-)
diff --git a/contrib/auto_explain/auto_explain.c
b/contrib/auto_explain/auto_explain.c
index 646cd0d42c..54d9a8c5e5 100644
--- a/contrib/auto_explain/auto_explain.c
+++ b/contrib/auto_explain/auto_explain.c
@@ -295,14 +295,10 @@ explain_ExecutorRun(QueryDesc *queryDesc, ScanDirection
direction,
prev_ExecutorRun(queryDesc, direction, count,
execute_once);
else
standard_ExecutorRun(queryDesc, direction, count,
execute_once);
- nesting_level--;
}
- PG_CATCH();
- {
+ PG_FINALLY({
nesting_level--;
- PG_RE_THROW();
- }
- PG_END_TRY();
+ });
}
/*
@@ -318,14 +314,10 @@ explain_ExecutorFinish(QueryDesc *queryDesc)
prev_ExecutorFinish(queryDesc);
else
standard_ExecutorFinish(queryDesc);
- nesting_level--;
}
- PG_CATCH();
- {
+ PG_FINALLY({
nesting_level--;
- PG_RE_THROW();
- }
- PG_END_TRY();
+ });
}
/*
diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 3b73ff13f1..068c2c602c 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -776,18 +776,11 @@ dblink_record_internal(FunctionCallInfo fcinfo, bool
is_async)
}
}
}
- PG_CATCH();
- {
+ PG_FINALLY({
/* if needed, close the connection to the database */
if (freeconn)
PQfinish(conn);
- PG_RE_THROW();
- }
- PG_END_TRY();
-
- /* if needed, close the connection to the database */
- if (freeconn)
- PQfinish(conn);
+ });
return (Datum) 0;
}
@@ -952,16 +945,11 @@ materializeResult(FunctionCallInfo fcinfo, PGconn *conn,
PGresult *res)
/* clean up and return the tuplestore */
tuplestore_donestoring(tupstore);
}
-
- PQclear(res);
}
- PG_CATCH();
- {
+ PG_FINALLY({
/* be sure to release the libpq result */
PQclear(res);
- PG_RE_THROW();
- }
- PG_END_TRY();
+ });
}
/*
@@ -1466,18 +1454,11 @@ dblink_exec(PG_FUNCTION_ARGS)
errmsg("statement returning results
not allowed")));
}
}
- PG_CATCH();
- {
+ PG_FINALLY({
/* if needed, close the connection to the database */
if (freeconn)
PQfinish(conn);
- PG_RE_THROW();
- }
- PG_END_TRY();
-
- /* if needed, close the connection to the database */
- if (freeconn)
- PQfinish(conn);
+ });
PG_RETURN_TEXT_P(sql_cmd_status);
}
diff --git a/contrib/hstore_plpython/hstore_plpython.c
b/contrib/hstore_plpython/hstore_plpython.c
index 2f24090ff3..9c5acd0ea1 100644
--- a/contrib/hstore_plpython/hstore_plpython.c
+++ b/contrib/hstore_plpython/hstore_plpython.c
@@ -177,17 +177,13 @@ plpython_to_hstore(PG_FUNCTION_ARGS)
pairs[i].isnull = false;
}
}
- Py_DECREF(items_v);
pcount = hstoreUniquePairs(pairs, pcount, &buflen);
out = hstorePairs(pairs, pcount, buflen);
}
- PG_CATCH();
- {
+ PG_FINALLY({
Py_DECREF(items_v);
- PG_RE_THROW();
- }
- PG_END_TRY();
+ });
PG_RETURN_POINTER(out);
}
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c
b/contrib/pg_stat_statements/pg_stat_statements.c
index 33f9a79f54..a6b19e6403 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -890,14 +890,10 @@ pgss_ExecutorRun(QueryDesc *queryDesc, ScanDirection
direction, uint64 count,
prev_ExecutorRun(queryDesc, direction, count,
execute_once);
else
standard_ExecutorRun(queryDesc, direction, count,
execute_once);
- nested_level--;
}
- PG_CATCH();
- {
+ PG_FINALLY({
nested_level--;
- PG_RE_THROW();
- }
- PG_END_TRY();
+ });
}
/*
@@ -913,14 +909,10 @@ pgss_ExecutorFinish(QueryDesc *queryDesc)
prev_ExecutorFinish(queryDesc);
else
standard_ExecutorFinish(queryDesc);
- nested_level--;
}
- PG_CATCH();
- {
+ PG_FINALLY({
nested_level--;
- PG_RE_THROW();
- }
- PG_END_TRY();
+ });
}
/*
@@ -1005,14 +997,10 @@ pgss_ProcessUtility(PlannedStmt *pstmt, const char
*queryString,
standard_ProcessUtility(pstmt, queryString,
context, params, queryEnv,
dest, completionTag);
- nested_level--;
}
- PG_CATCH();
- {
+ PG_FINALLY({
nested_level--;
- PG_RE_THROW();
- }
- PG_END_TRY();
+ });
INSTR_TIME_SET_CURRENT(duration);
INSTR_TIME_SUBTRACT(duration, start);
diff --git a/contrib/pg_trgm/trgm_regexp.c b/contrib/pg_trgm/trgm_regexp.c
index 547e7c094f..17743f5a8e 100644
--- a/contrib/pg_trgm/trgm_regexp.c
+++ b/contrib/pg_trgm/trgm_regexp.c
@@ -557,14 +557,9 @@ createTrgmNFA(text *text_re, Oid collation,
{
trg = createTrgmNFAInternal(®ex, graph, rcontext);
}
- PG_CATCH();
- {
+ PG_FINALLY({
pg_regfree(®ex);
- PG_RE_THROW();
- }
- PG_END_TRY();
-
- pg_regfree(®ex);
+ });
/* Clean up all the cruft we created */
MemoryContextSwitchTo(oldcontext);
diff --git a/contrib/postgres_fdw/connection.c
b/contrib/postgres_fdw/connection.c
index a6509932dc..067fc53d59 100644
--- a/contrib/postgres_fdw/connection.c
+++ b/contrib/postgres_fdw/connection.c
@@ -633,15 +633,10 @@ pgfdw_report_error(int elevel, PGresult *res, PGconn
*conn,
message_context ? errcontext("%s",
message_context) : 0,
sql ? errcontext("remote SQL command: %s",
sql) : 0));
}
- PG_CATCH();
- {
+ PG_FINALLY({
if (clear)
PQclear(res);
- PG_RE_THROW();
- }
- PG_END_TRY();
- if (clear)
- PQclear(res);
+ });
}
/*
diff --git a/contrib/sepgsql/hooks.c b/contrib/sepgsql/hooks.c
index 4249ed552c..430d179a2c 100644
--- a/contrib/sepgsql/hooks.c
+++ b/contrib/sepgsql/hooks.c
@@ -373,13 +373,9 @@ sepgsql_utility_command(PlannedStmt *pstmt,
context, params, queryEnv,
dest,
completionTag);
}
- PG_CATCH();
- {
+ PG_FINALLY({
sepgsql_context_info = saved_context_info;
- PG_RE_THROW();
- }
- PG_END_TRY();
- sepgsql_context_info = saved_context_info;
+ });
}
/*
diff --git a/contrib/sepgsql/label.c b/contrib/sepgsql/label.c
index acffc468d2..938eb72001 100644
--- a/contrib/sepgsql/label.c
+++ b/contrib/sepgsql/label.c
@@ -474,14 +474,9 @@ sepgsql_get_label(Oid classId, Oid objectId, int32 subId)
{
label = pstrdup(unlabeled);
}
- PG_CATCH();
- {
+ PG_FINALLY({
freecon(unlabeled);
- PG_RE_THROW();
- }
- PG_END_TRY();
-
- freecon(unlabeled);
+ });
}
return label;
}
@@ -609,13 +604,9 @@ sepgsql_mcstrans_in(PG_FUNCTION_ARGS)
{
result = pstrdup(raw_label);
}
- PG_CATCH();
- {
+ PG_FINALLY({
freecon(raw_label);
- PG_RE_THROW();
- }
- PG_END_TRY();
- freecon(raw_label);
+ });
PG_RETURN_TEXT_P(cstring_to_text(result));
}
@@ -649,13 +640,9 @@ sepgsql_mcstrans_out(PG_FUNCTION_ARGS)
{
result = pstrdup(qual_label);
}
- PG_CATCH();
- {
+ PG_FINALLY({
freecon(qual_label);
- PG_RE_THROW();
- }
- PG_END_TRY();
- freecon(qual_label);
+ });
PG_RETURN_TEXT_P(cstring_to_text(result));
}
@@ -860,13 +847,9 @@ exec_object_restorecon(struct selabel_handle *sehnd, Oid
catalogId)
SetSecurityLabel(&object, SEPGSQL_LABEL_TAG,
context);
}
- PG_CATCH();
- {
+ PG_FINALLY({
freecon(context);
- PG_RE_THROW();
- }
- PG_END_TRY();
- freecon(context);
+ });
}
else if (errno == ENOENT)
ereport(WARNING,
@@ -946,14 +929,9 @@ sepgsql_restorecon(PG_FUNCTION_ARGS)
exec_object_restorecon(sehnd, AttributeRelationId);
exec_object_restorecon(sehnd, ProcedureRelationId);
}
- PG_CATCH();
- {
+ PG_FINALLY({
selabel_close(sehnd);
- PG_RE_THROW();
- }
- PG_END_TRY();
-
- selabel_close(sehnd);
+ });
PG_RETURN_BOOL(true);
}
diff --git a/contrib/sepgsql/selinux.c b/contrib/sepgsql/selinux.c
index 47def00a46..db70d77bc2 100644
--- a/contrib/sepgsql/selinux.c
+++ b/contrib/sepgsql/selinux.c
@@ -873,13 +873,9 @@ sepgsql_compute_create(const char *scontext,
{
result = pstrdup(ncontext);
}
- PG_CATCH();
- {
+ PG_FINALLY({
freecon(ncontext);
- PG_RE_THROW();
- }
- PG_END_TRY();
- freecon(ncontext);
+ });
return result;
}
diff --git a/contrib/sepgsql/uavc.c b/contrib/sepgsql/uavc.c
index ea276ee0cc..37ceed8340 100644
--- a/contrib/sepgsql/uavc.c
+++ b/contrib/sepgsql/uavc.c
@@ -187,14 +187,9 @@ sepgsql_avc_unlabeled(void)
{
avc_unlabeled = MemoryContextStrdup(avc_mem_cxt,
unlabeled);
}
- PG_CATCH();
- {
+ PG_FINALLY({
freecon(unlabeled);
- PG_RE_THROW();
- }
- PG_END_TRY();
-
- freecon(unlabeled);
+ });
}
return avc_unlabeled;
}
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 8709e8c22c..62e1b4dc73 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3705,14 +3705,10 @@ reindex_index(Oid indexId, bool skip_constraint_checks,
char persistence,
/* Note: we do not need to re-establish pkey setting */
index_build(heapRelation, iRel, indexInfo, false, true, true);
}
- PG_CATCH();
- {
+ PG_FINALLY({
/* Make sure flag gets cleared on error exit */
ResetReindexProcessing();
- PG_RE_THROW();
- }
- PG_END_TRY();
- ResetReindexProcessing();
+ });
/*
* If the index is marked invalid/not-ready/dead (ie, it's from a failed
@@ -3954,14 +3950,10 @@ reindex_relation(Oid relid, int flags, int options)
doneIndexes = lappend_oid(doneIndexes,
indexOid);
}
}
- PG_CATCH();
- {
+ PG_FINALLY({
/* Make sure list gets cleared on error exit */
ResetReindexPending();
- PG_RE_THROW();
- }
- PG_END_TRY();
- ResetReindexPending();
+ });
if (is_pg_class)
RelationSetIndexList(rel, indexIds);
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index ee7c6d41b4..247cbf98a8 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -1867,8 +1867,7 @@ asyncQueueReadAllNotifications(void)
snapshot);
} while (!reachedStop);
}
- PG_CATCH();
- {
+ PG_FINALLY({
/* Update shared state */
LWLockAcquire(AsyncQueueLock, LW_SHARED);
QUEUE_BACKEND_POS(MyBackendId) = pos;
@@ -1878,20 +1877,7 @@ asyncQueueReadAllNotifications(void)
/* If we were the laziest backend, try to advance the tail
pointer */
if (advanceTail)
asyncQueueAdvanceTail();
-
- PG_RE_THROW();
- }
- PG_END_TRY();
-
- /* Update shared state */
- LWLockAcquire(AsyncQueueLock, LW_SHARED);
- QUEUE_BACKEND_POS(MyBackendId) = pos;
- advanceTail = QUEUE_POS_EQUAL(oldpos, QUEUE_TAIL);
- LWLockRelease(AsyncQueueLock);
-
- /* If we were the laziest backend, try to advance the tail pointer */
- if (advanceTail)
- asyncQueueAdvanceTail();
+ });
/* Done with snapshot */
UnregisterSnapshot(snapshot);
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 4aa8890fe8..de10453b4a 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -1850,13 +1850,9 @@ BeginCopyTo(ParseState *pstate,
{
cstate->copy_file =
AllocateFile(cstate->filename, PG_BINARY_W);
}
- PG_CATCH();
- {
+ PG_FINALLY({
umask(oumask);
- PG_RE_THROW();
- }
- PG_END_TRY();
- umask(oumask);
+ });
if (cstate->copy_file == NULL)
{
/* copy errno because ereport subfunctions
might change it */
diff --git a/src/backend/commands/event_trigger.c
b/src/backend/commands/event_trigger.c
index 3e7c1067d8..0e5bfc5f5b 100644
--- a/src/backend/commands/event_trigger.c
+++ b/src/backend/commands/event_trigger.c
@@ -935,13 +935,9 @@ EventTriggerSQLDrop(Node *parsetree)
{
EventTriggerInvoke(runlist, &trigdata);
}
- PG_CATCH();
- {
+ PG_FINALLY({
currentEventTriggerState->in_sql_drop = false;
- PG_RE_THROW();
- }
- PG_END_TRY();
- currentEventTriggerState->in_sql_drop = false;
+ });
/* Cleanup. */
list_free(runlist);
@@ -1008,16 +1004,10 @@ EventTriggerTableRewrite(Node *parsetree, Oid tableOid,
int reason)
{
EventTriggerInvoke(runlist, &trigdata);
}
- PG_CATCH();
- {
+ PG_FINALLY({
currentEventTriggerState->table_rewrite_oid = InvalidOid;
currentEventTriggerState->table_rewrite_reason = 0;
- PG_RE_THROW();
- }
- PG_END_TRY();
-
- currentEventTriggerState->table_rewrite_oid = InvalidOid;
- currentEventTriggerState->table_rewrite_reason = 0;
+ });
/* Cleanup. */
list_free(runlist);
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index 87e4dd8245..a9d64dc2f3 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -922,16 +922,10 @@ execute_extension_script(Oid extensionOid,
ExtensionControlFile *control,
execute_sql_string(c_sql);
}
- PG_CATCH();
- {
+ PG_FINALLY({
creating_extension = false;
CurrentExtensionObject = InvalidOid;
- PG_RE_THROW();
- }
- PG_END_TRY();
-
- creating_extension = false;
- CurrentExtensionObject = InvalidOid;
+ });
/*
* Restore the GUC variables we set above.
diff --git a/src/backend/commands/matview.c b/src/backend/commands/matview.c
index a171ebabf8..bc67f9932c 100644
--- a/src/backend/commands/matview.c
+++ b/src/backend/commands/matview.c
@@ -320,13 +320,9 @@ ExecRefreshMatView(RefreshMatViewStmt *stmt, const char
*queryString,
refresh_by_match_merge(matviewOid, OIDNewHeap, relowner,
save_sec_context);
}
- PG_CATCH();
- {
+ PG_FINALLY({
matview_maintenance_depth = old_depth;
- PG_RE_THROW();
- }
- PG_END_TRY();
- Assert(matview_maintenance_depth == old_depth);
+ });
}
else
{
diff --git a/src/backend/commands/subscriptioncmds.c
b/src/backend/commands/subscriptioncmds.c
index 9021463a4c..49fe891e48 100644
--- a/src/backend/commands/subscriptioncmds.c
+++ b/src/backend/commands/subscriptioncmds.c
@@ -474,16 +474,9 @@ CreateSubscription(CreateSubscriptionStmt *stmt, bool
isTopLevel)
slotname)));
}
}
- PG_CATCH();
- {
- /* Close the connection in case of failure. */
+ PG_FINALLY({
walrcv_disconnect(wrconn);
- PG_RE_THROW();
- }
- PG_END_TRY();
-
- /* And we are done with the remote side. */
- walrcv_disconnect(wrconn);
+ });
}
else
ereport(WARNING,
@@ -1002,15 +995,9 @@ DropSubscription(DropSubscriptionStmt *stmt, bool
isTopLevel)
walrcv_clear_result(res);
}
- PG_CATCH();
- {
- /* Close the connection in case of failure */
+ PG_FINALLY({
walrcv_disconnect(wrconn);
- PG_RE_THROW();
- }
- PG_END_TRY();
-
- walrcv_disconnect(wrconn);
+ });
pfree(cmd.data);
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index bcdd86ce92..eb3a5fb48d 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -2413,13 +2413,9 @@ ExecCallTriggerFunc(TriggerData *trigdata,
{
result = FunctionCallInvoke(&fcinfo);
}
- PG_CATCH();
- {
+ PG_FINALLY({
MyTriggerDepth--;
- PG_RE_THROW();
- }
- PG_END_TRY();
- MyTriggerDepth--;
+ });
pgstat_end_function_usage(&fcusage, true);
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index 25b3b0312c..897967a7ec 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -365,16 +365,10 @@ vacuum(int options, List *relations, VacuumParams *params,
}
}
}
- PG_CATCH();
- {
+ PG_FINALLY({
in_vacuum = false;
VacuumCostActive = false;
- PG_RE_THROW();
- }
- PG_END_TRY();
-
- in_vacuum = false;
- VacuumCostActive = false;
+ });
/*
* Finish up processing.
diff --git a/src/backend/libpq/be-fsstubs.c b/src/backend/libpq/be-fsstubs.c
index 0b802b54e4..fa5e4c6596 100644
--- a/src/backend/libpq/be-fsstubs.c
+++ b/src/backend/libpq/be-fsstubs.c
@@ -498,13 +498,9 @@ be_lo_export(PG_FUNCTION_ARGS)
fd = OpenTransientFilePerm(fnamebuf, O_CREAT | O_WRONLY |
O_TRUNC | PG_BINARY,
S_IRUSR |
S_IWUSR | S_IRGRP | S_IROTH);
}
- PG_CATCH();
- {
+ PG_FINALLY({
umask(oumask);
- PG_RE_THROW();
- }
- PG_END_TRY();
- umask(oumask);
+ });
if (fd < 0)
ereport(ERROR,
(errcode_for_file_access(),
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 970c94ee80..6b9e138414 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -1496,13 +1496,9 @@ ProcessUtilitySlow(ParseState *pstate,
address =
ExecRefreshMatView((RefreshMatViewStmt *) parsetree,
queryString, params, completionTag);
}
- PG_CATCH();
- {
+ PG_FINALLY({
EventTriggerUndoInhibitCommandCollection();
- PG_RE_THROW();
- }
- PG_END_TRY();
- EventTriggerUndoInhibitCommandCollection();
+ });
break;
case T_CreateTrigStmt:
@@ -1694,16 +1690,10 @@ ProcessUtilitySlow(ParseState *pstate,
EventTriggerDDLCommandEnd(parsetree);
}
}
- PG_CATCH();
- {
+ PG_FINALLY({
if (needCleanup)
EventTriggerEndCompleteQuery();
- PG_RE_THROW();
- }
- PG_END_TRY();
-
- if (needCleanup)
- EventTriggerEndCompleteQuery();
+ });
}
/*
diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c
index 37d85f71f3..3fe86d2e78 100644
--- a/src/backend/utils/adt/xml.c
+++ b/src/backend/utils/adt/xml.c
@@ -3705,15 +3705,10 @@ xml_xmlnodetoxmltype(xmlNodePtr cur, PgXmlErrorContext
*xmlerrcxt)
xmlNodeDump(buf, NULL, cur_copy, 0, 1);
result = xmlBuffer_to_xmltype(buf);
}
- PG_CATCH();
- {
+ PG_FINALLY({
xmlFreeNode(cur_copy);
xmlBufferFree(buf);
- PG_RE_THROW();
- }
- PG_END_TRY();
- xmlFreeNode(cur_copy);
- xmlBufferFree(buf);
+ });
}
else
{
@@ -3728,13 +3723,9 @@ xml_xmlnodetoxmltype(xmlNodePtr cur, PgXmlErrorContext
*xmlerrcxt)
result = (xmltype *) cstring_to_text(escaped);
pfree(escaped);
}
- PG_CATCH();
- {
+ PG_FINALLY({
xmlFree(str);
- PG_RE_THROW();
- }
- PG_END_TRY();
- xmlFree(str);
+ });
}
return result;
@@ -4523,13 +4514,9 @@ XmlTableGetValue(TableFuncScanState *state, int colnum,
{
cstr = pstrdup((char *) str);
}
- PG_CATCH();
- {
+ PG_FINALLY({
xmlFree(str);
- PG_RE_THROW();
- }
- PG_END_TRY();
- xmlFree(str);
+ });
}
else
{
diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h
index 33c6b53e27..9cf2bcd8a4 100644
--- a/src/include/utils/elog.h
+++ b/src/include/utils/elog.h
@@ -318,6 +318,36 @@ extern PGDLLIMPORT ErrorContextCallback
*error_context_stack;
error_context_stack = save_context_stack; \
} while (0)
+/*----------
+ * Variant API for the common case that the error recovery code and the
+ * cleanup in the normal code path are identical. Use like so:
+ *
+ * PG_TRY();
+ * {
+ * ... code that might throw ereport(ERROR) ...
+ * }
+ * PG_FINALLY(
+ * {
+ * ... cleanup code ...
+ * });
+ *
+ * The cleanup code will be run in either case, and any error will be rethrown
+ * afterwards. Note the slightly different bracketing.
+ */
+#define PG_FINALLY(code) \
+ } \
+ else \
+ { \
+ PG_exception_stack = save_exception_stack; \
+ error_context_stack = save_context_stack; \
+ do { code } while(0); \
+ PG_RE_THROW(); \
+ } \
+ PG_exception_stack = save_exception_stack; \
+ error_context_stack = save_context_stack; \
+ do { code } while(0); \
+ } while (0)
+
/*
* Some compilers understand pg_attribute_noreturn(); for other compilers,
* insert pg_unreachable() so that the compiler gets the point.
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index fe54b20903..4172a399cd 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1851,20 +1851,13 @@ plperl_call_handler(PG_FUNCTION_ARGS)
else
retval = plperl_func_handler(fcinfo);
}
- PG_CATCH();
- {
+ PG_FINALLY({
current_call_data = save_call_data;
activate_interpreter(oldinterp);
if (this_call_data.prodesc)
decrement_prodesc_refcount(this_call_data.prodesc);
- PG_RE_THROW();
- }
- PG_END_TRY();
+ });
- current_call_data = save_call_data;
- activate_interpreter(oldinterp);
- if (this_call_data.prodesc)
- decrement_prodesc_refcount(this_call_data.prodesc);
return retval;
}
@@ -1947,21 +1940,12 @@ plperl_inline_handler(PG_FUNCTION_ARGS)
if (SPI_finish() != SPI_OK_FINISH)
elog(ERROR, "SPI_finish() failed");
}
- PG_CATCH();
- {
+ PG_FINALLY({
if (desc.reference)
SvREFCNT_dec_current(desc.reference);
current_call_data = save_call_data;
activate_interpreter(oldinterp);
- PG_RE_THROW();
- }
- PG_END_TRY();
-
- if (desc.reference)
- SvREFCNT_dec_current(desc.reference);
-
- current_call_data = save_call_data;
- activate_interpreter(oldinterp);
+ });
error_context_stack = pl_error_context.previous;
diff --git a/src/pl/plpgsql/src/pl_handler.c b/src/pl/plpgsql/src/pl_handler.c
index 7d3647a12d..9a40111258 100644
--- a/src/pl/plpgsql/src/pl_handler.c
+++ b/src/pl/plpgsql/src/pl_handler.c
@@ -266,18 +266,11 @@ plpgsql_call_handler(PG_FUNCTION_ARGS)
else
retval = plpgsql_exec_function(func, fcinfo, NULL,
!nonatomic);
}
- PG_CATCH();
- {
- /* Decrement use-count, restore cur_estate, and propagate error
*/
+ PG_FINALLY({
+ /* Decrement use-count, restore cur_estate */
func->use_count--;
func->cur_estate = save_cur_estate;
- PG_RE_THROW();
- }
- PG_END_TRY();
-
- func->use_count--;
-
- func->cur_estate = save_cur_estate;
+ });
/*
* Disconnect from SPI manager
diff --git a/src/pl/plpython/plpy_cursorobject.c
b/src/pl/plpython/plpy_cursorobject.c
index 45ac25b2ae..0378d1f049 100644
--- a/src/pl/plpython/plpy_cursorobject.c
+++ b/src/pl/plpython/plpy_cursorobject.c
@@ -228,13 +228,9 @@ PLy_cursor_plan(PyObject *ob, PyObject *args)
plan->values[j] = PLy_output_convert(arg, elem,
&isnull);
nulls[j] = isnull ? 'n' : ' ';
}
- PG_CATCH();
- {
+ PG_FINALLY({
Py_DECREF(elem);
- PG_RE_THROW();
- }
- PG_END_TRY();
- Py_DECREF(elem);
+ });
}
portal = SPI_cursor_open(NULL, plan->plan, plan->values, nulls,
diff --git a/src/pl/plpython/plpy_elog.c b/src/pl/plpython/plpy_elog.c
index 3814a6c32d..b897c83ba6 100644
--- a/src/pl/plpython/plpy_elog.c
+++ b/src/pl/plpython/plpy_elog.c
@@ -141,7 +141,7 @@ PLy_elog_impl(int elevel, const char *fmt,...)
(constraint_name) ?
err_generic_string(PG_DIAG_CONSTRAINT_NAME,
constraint_name) : 0));
}
- PG_CATCH();
+ PG_FINALLY(
{
if (fmt)
pfree(emsg.data);
@@ -151,19 +151,7 @@ PLy_elog_impl(int elevel, const char *fmt,...)
pfree(tbmsg);
Py_XDECREF(exc);
Py_XDECREF(val);
-
- PG_RE_THROW();
- }
- PG_END_TRY();
-
- if (fmt)
- pfree(emsg.data);
- if (xmsg)
- pfree(xmsg);
- if (tbmsg)
- pfree(tbmsg);
- Py_XDECREF(exc);
- Py_XDECREF(val);
+ });
}
/*
diff --git a/src/pl/plpython/plpy_exec.c b/src/pl/plpython/plpy_exec.c
index 47ed95dcc6..9f601daec7 100644
--- a/src/pl/plpython/plpy_exec.c
+++ b/src/pl/plpython/plpy_exec.c
@@ -402,17 +402,10 @@ PLy_exec_trigger(FunctionCallInfo fcinfo, PLyProcedure
*proc)
}
}
}
- PG_CATCH();
- {
+ PG_FINALLY({
Py_XDECREF(plargs);
Py_XDECREF(plrv);
-
- PG_RE_THROW();
- }
- PG_END_TRY();
-
- Py_DECREF(plargs);
- Py_DECREF(plrv);
+ });
return rv;
}
@@ -1037,14 +1030,9 @@ PLy_procedure_call(PLyProcedure *proc, const char
*kargs, PyObject *vargs)
*/
Assert(list_length(explicit_subtransactions) >=
save_subxact_level);
}
- PG_CATCH();
- {
+ PG_FINALLY({
PLy_abort_open_subtransactions(save_subxact_level);
- PG_RE_THROW();
- }
- PG_END_TRY();
-
- PLy_abort_open_subtransactions(save_subxact_level);
+ });
/* If the Python code returned an error, propagate it */
if (rv == NULL)
diff --git a/src/pl/plpython/plpy_spi.c b/src/pl/plpython/plpy_spi.c
index 41155fc81e..9dc0e7c3f1 100644
--- a/src/pl/plpython/plpy_spi.c
+++ b/src/pl/plpython/plpy_spi.c
@@ -249,13 +249,10 @@ PLy_spi_execute_plan(PyObject *ob, PyObject *list, long
limit)
plan->values[j] = PLy_output_convert(arg, elem,
&isnull);
nulls[j] = isnull ? 'n' : ' ';
}
- PG_CATCH();
+ PG_FINALLY(
{
Py_DECREF(elem);
- PG_RE_THROW();
- }
- PG_END_TRY();
- Py_DECREF(elem);
+ });
}
rv = SPI_execute_plan(plan->plan, plan->values, nulls,
diff --git a/src/pl/plpython/plpy_typeio.c b/src/pl/plpython/plpy_typeio.c
index d6a6a849c3..99e8fc0602 100644
--- a/src/pl/plpython/plpy_typeio.c
+++ b/src/pl/plpython/plpy_typeio.c
@@ -918,14 +918,10 @@ PLyObject_ToBytea(PLyObToDatum *arg, PyObject *plrv,
memcpy(VARDATA(result), plrv_sc, len);
rv = PointerGetDatum(result);
}
- PG_CATCH();
+ PG_FINALLY(
{
Py_XDECREF(plrv_so);
- PG_RE_THROW();
- }
- PG_END_TRY();
-
- Py_XDECREF(plrv_so);
+ });
return rv;
}
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index 3b1454f833..e7f0a39014 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -765,9 +765,10 @@ pltcl_handler(PG_FUNCTION_ARGS, bool pltrusted)
retval = pltcl_func_handler(fcinfo,
¤t_call_state, pltrusted);
}
}
- PG_CATCH();
+ PG_FINALLY(
{
/* Restore static pointer, then clean up the prodesc refcount
if any */
+ /* (We're being paranoid in case an error is thrown in context
deletion) */
pltcl_current_call_state = save_call_state;
if (current_call_state.prodesc != NULL)
{
@@ -775,19 +776,7 @@ pltcl_handler(PG_FUNCTION_ARGS, bool pltrusted)
if (--current_call_state.prodesc->fn_refcount == 0)
MemoryContextDelete(current_call_state.prodesc->fn_cxt);
}
- PG_RE_THROW();
- }
- PG_END_TRY();
-
- /* Restore static pointer, then clean up the prodesc refcount if any */
- /* (We're being paranoid in case an error is thrown in context
deletion) */
- pltcl_current_call_state = save_call_state;
- if (current_call_state.prodesc != NULL)
- {
- Assert(current_call_state.prodesc->fn_refcount > 0);
- if (--current_call_state.prodesc->fn_refcount == 0)
- MemoryContextDelete(current_call_state.prodesc->fn_cxt);
- }
+ });
return retval;
}
--
2.20.0