aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Eisentraut <peter@eisentraut.org>2019-11-01 11:09:52 +0100
committerPeter Eisentraut <peter@eisentraut.org>2019-11-01 11:18:03 +0100
commit604bd3671121b51f977de146ed95484c2297fb3e (patch)
tree829045453c054befb9d795c33765501e2f4522f3
parent73025140885c889410b9bfc4a30a3866396fc5db (diff)
downloadpostgresql-604bd3671121b51f977de146ed95484c2297fb3e.tar.gz
postgresql-604bd3671121b51f977de146ed95484c2297fb3e.zip
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
-rw-r--r--contrib/auto_explain/auto_explain.c8
-rw-r--r--contrib/dblink/dblink.c19
-rw-r--r--contrib/hstore_plpython/hstore_plpython.c5
-rw-r--r--contrib/jsonb_plpython/jsonb_plpython.c5
-rw-r--r--contrib/pg_stat_statements/pg_stat_statements.c12
-rw-r--r--contrib/pg_trgm/trgm_regexp.c5
-rw-r--r--contrib/postgres_fdw/connection.c5
-rw-r--r--contrib/postgres_fdw/postgres_fdw.c25
-rw-r--r--contrib/sepgsql/hooks.c4
-rw-r--r--contrib/sepgsql/label.c22
-rw-r--r--contrib/sepgsql/selinux.c4
-rw-r--r--contrib/sepgsql/uavc.c5
-rw-r--r--src/backend/catalog/index.c8
-rw-r--r--src/backend/commands/async.c9
-rw-r--r--src/backend/commands/copy.c4
-rw-r--r--src/backend/commands/event_trigger.c10
-rw-r--r--src/backend/commands/extension.c6
-rw-r--r--src/backend/commands/subscriptioncmds.c13
-rw-r--r--src/backend/commands/trigger.c4
-rw-r--r--src/backend/commands/vacuum.c6
-rw-r--r--src/backend/libpq/be-fsstubs.c4
-rw-r--r--src/backend/tcop/utility.c10
-rw-r--r--src/backend/utils/adt/xml.c20
-rw-r--r--src/include/utils/elog.h46
-rw-r--r--src/pl/plperl/plperl.c16
-rw-r--r--src/pl/plpgsql/src/pl_handler.c9
-rw-r--r--src/pl/plpython/plpy_cursorobject.c4
-rw-r--r--src/pl/plpython/plpy_elog.c13
-rw-r--r--src/pl/plpython/plpy_exec.c12
-rw-r--r--src/pl/plpython/plpy_spi.c4
-rw-r--r--src/pl/plpython/plpy_typeio.c5
-rw-r--r--src/pl/tcl/pltcl.c14
32 files changed, 91 insertions, 245 deletions
diff --git a/contrib/auto_explain/auto_explain.c b/contrib/auto_explain/auto_explain.c
index a9536c2de05..f118dbaedd7 100644
--- a/contrib/auto_explain/auto_explain.c
+++ b/contrib/auto_explain/auto_explain.c
@@ -320,12 +320,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();
}
@@ -343,12 +341,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 54b7bf952f3..7e225589a9b 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -776,19 +776,14 @@ 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,14 +947,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();
}
@@ -1464,19 +1456,14 @@ 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 4dee5697403..39bad558023 100644
--- a/contrib/hstore_plpython/hstore_plpython.c
+++ b/contrib/hstore_plpython/hstore_plpython.c
@@ -180,14 +180,11 @@ plpython_to_hstore(PG_FUNCTION_ARGS)
pcount = hstoreUniquePairs(pairs, pcount, &buflen);
out = hstorePairs(pairs, pcount, buflen);
}
- PG_CATCH();
+ PG_FINALLY();
{
Py_DECREF(items);
- PG_RE_THROW();
}
PG_END_TRY();
- Py_DECREF(items);
-
PG_RETURN_POINTER(out);
}
diff --git a/contrib/jsonb_plpython/jsonb_plpython.c b/contrib/jsonb_plpython/jsonb_plpython.c
index ecaa4c6f92b..b41c738ad62 100644
--- a/contrib/jsonb_plpython/jsonb_plpython.c
+++ b/contrib/jsonb_plpython/jsonb_plpython.c
@@ -307,15 +307,12 @@ PLyMapping_ToJsonbValue(PyObject *obj, JsonbParseState **jsonb_state)
out = pushJsonbValue(jsonb_state, WJB_END_OBJECT, NULL);
}
- PG_CATCH();
+ PG_FINALLY();
{
Py_DECREF(items);
- PG_RE_THROW();
}
PG_END_TRY();
- Py_DECREF(items);
-
return out;
}
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 221b47298ce..63b5888ebbc 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -892,12 +892,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();
}
@@ -915,12 +913,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();
}
@@ -1007,12 +1003,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();
diff --git a/contrib/pg_trgm/trgm_regexp.c b/contrib/pg_trgm/trgm_regexp.c
index 7965a29c9f9..e65e6838230 100644
--- a/contrib/pg_trgm/trgm_regexp.c
+++ b/contrib/pg_trgm/trgm_regexp.c
@@ -555,15 +555,12 @@ 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);
MemoryContextDelete(tmpcontext);
diff --git a/contrib/postgres_fdw/connection.c b/contrib/postgres_fdw/connection.c
index 12f9dd35be8..7cd69cc7091 100644
--- a/contrib/postgres_fdw/connection.c
+++ b/contrib/postgres_fdw/connection.c
@@ -631,15 +631,12 @@ 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/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index 32366641a3e..fa142960eb5 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -3155,15 +3155,11 @@ get_remote_estimate(const char *sql, PGconn *conn,
startup_cost, total_cost, rows, width);
if (n != 4)
elog(ERROR, "could not interpret EXPLAIN output: \"%s\"", line);
-
- PQclear(res);
- res = NULL;
}
- PG_CATCH();
+ PG_FINALLY();
{
if (res)
PQclear(res);
- PG_RE_THROW();
}
PG_END_TRY();
}
@@ -3383,15 +3379,11 @@ fetch_more_data(ForeignScanState *node)
/* Must be EOF if we didn't get as many tuples as we asked for. */
fsstate->eof_reached = (numrows < fsstate->fetch_size);
-
- PQclear(res);
- res = NULL;
}
- PG_CATCH();
+ PG_FINALLY();
{
if (res)
PQclear(res);
- PG_RE_THROW();
}
PG_END_TRY();
@@ -4404,15 +4396,11 @@ postgresAnalyzeForeignTable(Relation relation,
if (PQntuples(res) != 1 || PQnfields(res) != 1)
elog(ERROR, "unexpected result from deparseAnalyzeSizeSql query");
*totalpages = strtoul(PQgetvalue(res, 0, 0), NULL, 10);
-
- PQclear(res);
- res = NULL;
}
- PG_CATCH();
+ PG_FINALLY();
{
if (res)
PQclear(res);
- PG_RE_THROW();
}
PG_END_TRY();
@@ -4925,16 +4913,11 @@ postgresImportForeignSchema(ImportForeignSchemaStmt *stmt, Oid serverOid)
commands = lappend(commands, pstrdup(buf.data));
}
-
- /* Clean up */
- PQclear(res);
- res = NULL;
}
- PG_CATCH();
+ PG_FINALLY();
{
if (res)
PQclear(res);
- PG_RE_THROW();
}
PG_END_TRY();
diff --git a/contrib/sepgsql/hooks.c b/contrib/sepgsql/hooks.c
index 992c70e8a06..49f32ac4d33 100644
--- a/contrib/sepgsql/hooks.c
+++ b/contrib/sepgsql/hooks.c
@@ -372,13 +372,11 @@ 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 d2505f7f343..d8a1d129d29 100644
--- a/contrib/sepgsql/label.c
+++ b/contrib/sepgsql/label.c
@@ -465,14 +465,11 @@ 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;
}
@@ -600,13 +597,11 @@ 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));
}
@@ -640,13 +635,11 @@ 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));
}
@@ -851,13 +844,11 @@ 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,
@@ -937,14 +928,11 @@ 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 192aabea0b3..b7c489cc336 100644
--- a/contrib/sepgsql/selinux.c
+++ b/contrib/sepgsql/selinux.c
@@ -871,13 +871,11 @@ 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 8ce0bc631b7..f5279cc9b6e 100644
--- a/contrib/sepgsql/uavc.c
+++ b/contrib/sepgsql/uavc.c
@@ -181,14 +181,11 @@ 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 f6c31ccd766..7c34509696d 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3449,14 +3449,12 @@ 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, 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
@@ -3676,14 +3674,12 @@ reindex_relation(Oid relid, int flags, int options)
i++;
}
}
- PG_CATCH();
+ PG_FINALLY();
{
/* Make sure list gets cleared on error exit */
ResetReindexPending();
- PG_RE_THROW();
}
PG_END_TRY();
- ResetReindexPending();
/*
* Close rel, but continue to hold the lock.
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index d0649d2e3ef..a3209d076b3 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -2028,22 +2028,15 @@ asyncQueueReadAllNotifications(void)
snapshot);
} while (!reachedStop);
}
- PG_CATCH();
+ PG_FINALLY();
{
/* Update shared state */
LWLockAcquire(AsyncQueueLock, LW_SHARED);
QUEUE_BACKEND_POS(MyBackendId) = pos;
LWLockRelease(AsyncQueueLock);
-
- PG_RE_THROW();
}
PG_END_TRY();
- /* Update shared state */
- LWLockAcquire(AsyncQueueLock, LW_SHARED);
- QUEUE_BACKEND_POS(MyBackendId) = pos;
- LWLockRelease(AsyncQueueLock);
-
/* Done with snapshot */
UnregisterSnapshot(snapshot);
}
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 3aeef30b281..e17d8c760f7 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -1916,13 +1916,11 @@ 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 f7ee9838f7f..0301ae1ddd9 100644
--- a/src/backend/commands/event_trigger.c
+++ b/src/backend/commands/event_trigger.c
@@ -934,13 +934,11 @@ 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);
@@ -1007,17 +1005,13 @@ 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 f7202cc9e7d..a04b0c9e579 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -942,17 +942,13 @@ 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/subscriptioncmds.c b/src/backend/commands/subscriptioncmds.c
index 2e67a5889e5..14191957665 100644
--- a/src/backend/commands/subscriptioncmds.c
+++ b/src/backend/commands/subscriptioncmds.c
@@ -493,16 +493,11 @@ CreateSubscription(CreateSubscriptionStmt *stmt, bool isTopLevel)
slotname)));
}
}
- PG_CATCH();
+ PG_FINALLY();
{
- /* Close the connection in case of failure. */
walrcv_disconnect(wrconn);
- PG_RE_THROW();
}
PG_END_TRY();
-
- /* And we are done with the remote side. */
- walrcv_disconnect(wrconn);
}
else
ereport(WARNING,
@@ -1023,16 +1018,12 @@ DropSubscription(DropSubscriptionStmt *stmt, bool isTopLevel)
walrcv_clear_result(res);
}
- PG_CATCH();
+ PG_FINALLY();
{
- /* Close the connection in case of failure */
walrcv_disconnect(wrconn);
- PG_RE_THROW();
}
PG_END_TRY();
- walrcv_disconnect(wrconn);
-
pfree(cmd.data);
table_close(rel, NoLock);
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 7ba859d446d..0b84de59437 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -2431,13 +2431,11 @@ 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 4b67b40b285..da1da234000 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -430,17 +430,13 @@ vacuum(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 b0ece7ec257..1ee96c0b9fc 100644
--- a/src/backend/libpq/be-fsstubs.c
+++ b/src/backend/libpq/be-fsstubs.c
@@ -503,13 +503,11 @@ 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 c6faa6619d2..f2269ad35ca 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -1514,13 +1514,11 @@ 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:
@@ -1716,16 +1714,12 @@ 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 0280c2625c6..c397461ad5d 100644
--- a/src/backend/utils/adt/xml.c
+++ b/src/backend/utils/adt/xml.c
@@ -1193,13 +1193,11 @@ xml_pstrdup_and_free(xmlChar *str)
{
result = pstrdup((char *) str);
}
- PG_CATCH();
+ PG_FINALLY();
{
xmlFree(str);
- PG_RE_THROW();
}
PG_END_TRY();
- xmlFree(str);
}
else
result = NULL;
@@ -3866,19 +3864,14 @@ xml_xmlnodetoxmltype(xmlNodePtr cur, PgXmlErrorContext *xmlerrcxt)
result = xmlBuffer_to_xmltype(buf);
}
- PG_CATCH();
+ PG_FINALLY()
{
if (nodefree)
nodefree(cur_copy);
if (buf)
xmlBufferFree(buf);
- PG_RE_THROW();
}
PG_END_TRY();
-
- if (nodefree)
- nodefree(cur_copy);
- xmlBufferFree(buf);
}
else
{
@@ -3893,13 +3886,11 @@ 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;
@@ -4734,16 +4725,13 @@ XmlTableGetValue(TableFuncScanState *state, int colnum,
state->typioparams[colnum],
typmod);
}
- PG_CATCH();
+ PG_FINALLY();
{
if (xpathobj != NULL)
xmlXPathFreeObject(xpathobj);
- PG_RE_THROW();
}
PG_END_TRY();
- xmlXPathFreeObject(xpathobj);
-
return result;
#else
NO_XML_SUPPORT();
diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h
index ba0b7f6f79c..853c2e0709e 100644
--- a/src/include/utils/elog.h
+++ b/src/include/utils/elog.h
@@ -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)
/*
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index c480999c51d..f0fb3085523 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1862,20 +1862,15 @@ 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;
}
@@ -1958,22 +1953,15 @@ 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;
PG_RETURN_VOID();
diff --git a/src/pl/plpgsql/src/pl_handler.c b/src/pl/plpgsql/src/pl_handler.c
index e92deb32ca4..1b592c8a525 100644
--- a/src/pl/plpgsql/src/pl_handler.c
+++ b/src/pl/plpgsql/src/pl_handler.c
@@ -264,19 +264,14 @@ plpgsql_call_handler(PG_FUNCTION_ARGS)
else
retval = plpgsql_exec_function(func, fcinfo, NULL, !nonatomic);
}
- PG_CATCH();
+ PG_FINALLY();
{
- /* Decrement use-count, restore cur_estate, and propagate error */
+ /* 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 e4d543a4d46..b44ce7e225f 100644
--- a/src/pl/plpython/plpy_cursorobject.c
+++ b/src/pl/plpython/plpy_cursorobject.c
@@ -228,13 +228,11 @@ 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 25930f99d78..15cc444af8e 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,8 @@ 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 920322e912b..6994d7c10b9 100644
--- a/src/pl/plpython/plpy_exec.c
+++ b/src/pl/plpython/plpy_exec.c
@@ -403,18 +403,13 @@ 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;
}
@@ -1052,15 +1047,12 @@ 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)
PLy_elog(ERROR, NULL);
diff --git a/src/pl/plpython/plpy_spi.c b/src/pl/plpython/plpy_spi.c
index 2fe435d42b0..ed2eee0603a 100644
--- a/src/pl/plpython/plpy_spi.c
+++ b/src/pl/plpython/plpy_spi.c
@@ -249,13 +249,11 @@ 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 371e534fd22..589c76e7a76 100644
--- a/src/pl/plpython/plpy_typeio.c
+++ b/src/pl/plpython/plpy_typeio.c
@@ -925,15 +925,12 @@ 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 8277d1ea857..fccd22b4f51 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,20 +776,9 @@ 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;
}