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 <pete...@gmx.net>
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(&regex, graph, rcontext);
        }
-       PG_CATCH();
-       {
+       PG_FINALLY({
                pg_regfree(&regex);
-               PG_RE_THROW();
-       }
-       PG_END_TRY();
-
-       pg_regfree(&regex);
+       });
 
        /* 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, 
&current_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

Reply via email to