PG_FINALLY

This gives an alternative way of catching exceptions, for the common
case where the cleanup code is the same in the error and non-error
cases.  So instead of

    PG_TRY();
    {
        ... code that might throw ereport(ERROR) ...
    }
    PG_CATCH();
    {
        cleanup();
	PG_RE_THROW();
    }
    PG_END_TRY();
    cleanup();

one can write

    PG_TRY();
    {
        ... code that might throw ereport(ERROR) ...
    }
    PG_FINALLY();
    {
        cleanup();
    }
    PG_END_TRY();

Discussion: https://www.postgresql.org/message-id/flat/95a822c3-728b-af0e-d7e5-71890507ae0c%402ndquadrant.com
This commit is contained in:
Peter Eisentraut 2019-11-01 11:09:52 +01:00
parent 7302514088
commit 604bd36711
32 changed files with 91 additions and 245 deletions

View File

@ -320,12 +320,10 @@ explain_ExecutorRun(QueryDesc *queryDesc, ScanDirection direction,
prev_ExecutorRun(queryDesc, direction, count, execute_once); prev_ExecutorRun(queryDesc, direction, count, execute_once);
else else
standard_ExecutorRun(queryDesc, direction, count, execute_once); standard_ExecutorRun(queryDesc, direction, count, execute_once);
nesting_level--;
} }
PG_CATCH(); PG_FINALLY();
{ {
nesting_level--; nesting_level--;
PG_RE_THROW();
} }
PG_END_TRY(); PG_END_TRY();
} }
@ -343,12 +341,10 @@ explain_ExecutorFinish(QueryDesc *queryDesc)
prev_ExecutorFinish(queryDesc); prev_ExecutorFinish(queryDesc);
else else
standard_ExecutorFinish(queryDesc); standard_ExecutorFinish(queryDesc);
nesting_level--;
} }
PG_CATCH(); PG_FINALLY();
{ {
nesting_level--; nesting_level--;
PG_RE_THROW();
} }
PG_END_TRY(); PG_END_TRY();
} }

View File

@ -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 needed, close the connection to the database */
if (freeconn) if (freeconn)
PQfinish(conn); PQfinish(conn);
PG_RE_THROW();
} }
PG_END_TRY(); PG_END_TRY();
/* if needed, close the connection to the database */
if (freeconn)
PQfinish(conn);
return (Datum) 0; return (Datum) 0;
} }
@ -952,14 +947,11 @@ materializeResult(FunctionCallInfo fcinfo, PGconn *conn, PGresult *res)
/* clean up and return the tuplestore */ /* clean up and return the tuplestore */
tuplestore_donestoring(tupstore); tuplestore_donestoring(tupstore);
} }
PQclear(res);
} }
PG_CATCH(); PG_FINALLY();
{ {
/* be sure to release the libpq result */ /* be sure to release the libpq result */
PQclear(res); PQclear(res);
PG_RE_THROW();
} }
PG_END_TRY(); PG_END_TRY();
} }
@ -1464,19 +1456,14 @@ dblink_exec(PG_FUNCTION_ARGS)
errmsg("statement returning results not allowed"))); errmsg("statement returning results not allowed")));
} }
} }
PG_CATCH(); PG_FINALLY();
{ {
/* if needed, close the connection to the database */ /* if needed, close the connection to the database */
if (freeconn) if (freeconn)
PQfinish(conn); PQfinish(conn);
PG_RE_THROW();
} }
PG_END_TRY(); PG_END_TRY();
/* if needed, close the connection to the database */
if (freeconn)
PQfinish(conn);
PG_RETURN_TEXT_P(sql_cmd_status); PG_RETURN_TEXT_P(sql_cmd_status);
} }

View File

@ -180,14 +180,11 @@ plpython_to_hstore(PG_FUNCTION_ARGS)
pcount = hstoreUniquePairs(pairs, pcount, &buflen); pcount = hstoreUniquePairs(pairs, pcount, &buflen);
out = hstorePairs(pairs, pcount, buflen); out = hstorePairs(pairs, pcount, buflen);
} }
PG_CATCH(); PG_FINALLY();
{ {
Py_DECREF(items); Py_DECREF(items);
PG_RE_THROW();
} }
PG_END_TRY(); PG_END_TRY();
Py_DECREF(items);
PG_RETURN_POINTER(out); PG_RETURN_POINTER(out);
} }

View File

@ -307,15 +307,12 @@ PLyMapping_ToJsonbValue(PyObject *obj, JsonbParseState **jsonb_state)
out = pushJsonbValue(jsonb_state, WJB_END_OBJECT, NULL); out = pushJsonbValue(jsonb_state, WJB_END_OBJECT, NULL);
} }
PG_CATCH(); PG_FINALLY();
{ {
Py_DECREF(items); Py_DECREF(items);
PG_RE_THROW();
} }
PG_END_TRY(); PG_END_TRY();
Py_DECREF(items);
return out; return out;
} }

View File

@ -892,12 +892,10 @@ pgss_ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count,
prev_ExecutorRun(queryDesc, direction, count, execute_once); prev_ExecutorRun(queryDesc, direction, count, execute_once);
else else
standard_ExecutorRun(queryDesc, direction, count, execute_once); standard_ExecutorRun(queryDesc, direction, count, execute_once);
nested_level--;
} }
PG_CATCH(); PG_FINALLY();
{ {
nested_level--; nested_level--;
PG_RE_THROW();
} }
PG_END_TRY(); PG_END_TRY();
} }
@ -915,12 +913,10 @@ pgss_ExecutorFinish(QueryDesc *queryDesc)
prev_ExecutorFinish(queryDesc); prev_ExecutorFinish(queryDesc);
else else
standard_ExecutorFinish(queryDesc); standard_ExecutorFinish(queryDesc);
nested_level--;
} }
PG_CATCH(); PG_FINALLY();
{ {
nested_level--; nested_level--;
PG_RE_THROW();
} }
PG_END_TRY(); PG_END_TRY();
} }
@ -1007,12 +1003,10 @@ pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
standard_ProcessUtility(pstmt, queryString, standard_ProcessUtility(pstmt, queryString,
context, params, queryEnv, context, params, queryEnv,
dest, completionTag); dest, completionTag);
nested_level--;
} }
PG_CATCH(); PG_FINALLY();
{ {
nested_level--; nested_level--;
PG_RE_THROW();
} }
PG_END_TRY(); PG_END_TRY();

View File

@ -555,15 +555,12 @@ createTrgmNFA(text *text_re, Oid collation,
{ {
trg = createTrgmNFAInternal(&regex, graph, rcontext); trg = createTrgmNFAInternal(&regex, graph, rcontext);
} }
PG_CATCH(); PG_FINALLY();
{ {
pg_regfree(&regex); pg_regfree(&regex);
PG_RE_THROW();
} }
PG_END_TRY(); PG_END_TRY();
pg_regfree(&regex);
/* Clean up all the cruft we created */ /* Clean up all the cruft we created */
MemoryContextSwitchTo(oldcontext); MemoryContextSwitchTo(oldcontext);
MemoryContextDelete(tmpcontext); MemoryContextDelete(tmpcontext);

View File

@ -631,15 +631,12 @@ pgfdw_report_error(int elevel, PGresult *res, PGconn *conn,
message_context ? errcontext("%s", message_context) : 0, message_context ? errcontext("%s", message_context) : 0,
sql ? errcontext("remote SQL command: %s", sql) : 0)); sql ? errcontext("remote SQL command: %s", sql) : 0));
} }
PG_CATCH(); PG_FINALLY();
{ {
if (clear) if (clear)
PQclear(res); PQclear(res);
PG_RE_THROW();
} }
PG_END_TRY(); PG_END_TRY();
if (clear)
PQclear(res);
} }
/* /*

View File

@ -3155,15 +3155,11 @@ get_remote_estimate(const char *sql, PGconn *conn,
startup_cost, total_cost, rows, width); startup_cost, total_cost, rows, width);
if (n != 4) if (n != 4)
elog(ERROR, "could not interpret EXPLAIN output: \"%s\"", line); elog(ERROR, "could not interpret EXPLAIN output: \"%s\"", line);
PQclear(res);
res = NULL;
} }
PG_CATCH(); PG_FINALLY();
{ {
if (res) if (res)
PQclear(res); PQclear(res);
PG_RE_THROW();
} }
PG_END_TRY(); 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. */ /* Must be EOF if we didn't get as many tuples as we asked for. */
fsstate->eof_reached = (numrows < fsstate->fetch_size); fsstate->eof_reached = (numrows < fsstate->fetch_size);
PQclear(res);
res = NULL;
} }
PG_CATCH(); PG_FINALLY();
{ {
if (res) if (res)
PQclear(res); PQclear(res);
PG_RE_THROW();
} }
PG_END_TRY(); PG_END_TRY();
@ -4404,15 +4396,11 @@ postgresAnalyzeForeignTable(Relation relation,
if (PQntuples(res) != 1 || PQnfields(res) != 1) if (PQntuples(res) != 1 || PQnfields(res) != 1)
elog(ERROR, "unexpected result from deparseAnalyzeSizeSql query"); elog(ERROR, "unexpected result from deparseAnalyzeSizeSql query");
*totalpages = strtoul(PQgetvalue(res, 0, 0), NULL, 10); *totalpages = strtoul(PQgetvalue(res, 0, 0), NULL, 10);
PQclear(res);
res = NULL;
} }
PG_CATCH(); PG_FINALLY();
{ {
if (res) if (res)
PQclear(res); PQclear(res);
PG_RE_THROW();
} }
PG_END_TRY(); PG_END_TRY();
@ -4925,16 +4913,11 @@ postgresImportForeignSchema(ImportForeignSchemaStmt *stmt, Oid serverOid)
commands = lappend(commands, pstrdup(buf.data)); commands = lappend(commands, pstrdup(buf.data));
} }
/* Clean up */
PQclear(res);
res = NULL;
} }
PG_CATCH(); PG_FINALLY();
{ {
if (res) if (res)
PQclear(res); PQclear(res);
PG_RE_THROW();
} }
PG_END_TRY(); PG_END_TRY();

View File

@ -372,13 +372,11 @@ sepgsql_utility_command(PlannedStmt *pstmt,
context, params, queryEnv, context, params, queryEnv,
dest, completionTag); dest, completionTag);
} }
PG_CATCH(); PG_FINALLY();
{ {
sepgsql_context_info = saved_context_info; sepgsql_context_info = saved_context_info;
PG_RE_THROW();
} }
PG_END_TRY(); PG_END_TRY();
sepgsql_context_info = saved_context_info;
} }
/* /*

View File

@ -465,14 +465,11 @@ sepgsql_get_label(Oid classId, Oid objectId, int32 subId)
{ {
label = pstrdup(unlabeled); label = pstrdup(unlabeled);
} }
PG_CATCH(); PG_FINALLY();
{ {
freecon(unlabeled); freecon(unlabeled);
PG_RE_THROW();
} }
PG_END_TRY(); PG_END_TRY();
freecon(unlabeled);
} }
return label; return label;
} }
@ -600,13 +597,11 @@ sepgsql_mcstrans_in(PG_FUNCTION_ARGS)
{ {
result = pstrdup(raw_label); result = pstrdup(raw_label);
} }
PG_CATCH(); PG_FINALLY();
{ {
freecon(raw_label); freecon(raw_label);
PG_RE_THROW();
} }
PG_END_TRY(); PG_END_TRY();
freecon(raw_label);
PG_RETURN_TEXT_P(cstring_to_text(result)); PG_RETURN_TEXT_P(cstring_to_text(result));
} }
@ -640,13 +635,11 @@ sepgsql_mcstrans_out(PG_FUNCTION_ARGS)
{ {
result = pstrdup(qual_label); result = pstrdup(qual_label);
} }
PG_CATCH(); PG_FINALLY();
{ {
freecon(qual_label); freecon(qual_label);
PG_RE_THROW();
} }
PG_END_TRY(); PG_END_TRY();
freecon(qual_label);
PG_RETURN_TEXT_P(cstring_to_text(result)); 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); SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, context);
} }
PG_CATCH(); PG_FINALLY();
{ {
freecon(context); freecon(context);
PG_RE_THROW();
} }
PG_END_TRY(); PG_END_TRY();
freecon(context);
} }
else if (errno == ENOENT) else if (errno == ENOENT)
ereport(WARNING, ereport(WARNING,
@ -937,14 +928,11 @@ sepgsql_restorecon(PG_FUNCTION_ARGS)
exec_object_restorecon(sehnd, AttributeRelationId); exec_object_restorecon(sehnd, AttributeRelationId);
exec_object_restorecon(sehnd, ProcedureRelationId); exec_object_restorecon(sehnd, ProcedureRelationId);
} }
PG_CATCH(); PG_FINALLY();
{ {
selabel_close(sehnd); selabel_close(sehnd);
PG_RE_THROW();
} }
PG_END_TRY(); PG_END_TRY();
selabel_close(sehnd);
PG_RETURN_BOOL(true); PG_RETURN_BOOL(true);
} }

View File

@ -871,13 +871,11 @@ sepgsql_compute_create(const char *scontext,
{ {
result = pstrdup(ncontext); result = pstrdup(ncontext);
} }
PG_CATCH(); PG_FINALLY();
{ {
freecon(ncontext); freecon(ncontext);
PG_RE_THROW();
} }
PG_END_TRY(); PG_END_TRY();
freecon(ncontext);
return result; return result;
} }

View File

@ -181,14 +181,11 @@ sepgsql_avc_unlabeled(void)
{ {
avc_unlabeled = MemoryContextStrdup(avc_mem_cxt, unlabeled); avc_unlabeled = MemoryContextStrdup(avc_mem_cxt, unlabeled);
} }
PG_CATCH(); PG_FINALLY();
{ {
freecon(unlabeled); freecon(unlabeled);
PG_RE_THROW();
} }
PG_END_TRY(); PG_END_TRY();
freecon(unlabeled);
} }
return avc_unlabeled; return avc_unlabeled;
} }

View File

@ -3449,14 +3449,12 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
/* Note: we do not need to re-establish pkey setting */ /* Note: we do not need to re-establish pkey setting */
index_build(heapRelation, iRel, indexInfo, true, true); index_build(heapRelation, iRel, indexInfo, true, true);
} }
PG_CATCH(); PG_FINALLY();
{ {
/* Make sure flag gets cleared on error exit */ /* Make sure flag gets cleared on error exit */
ResetReindexProcessing(); ResetReindexProcessing();
PG_RE_THROW();
} }
PG_END_TRY(); PG_END_TRY();
ResetReindexProcessing();
/* /*
* If the index is marked invalid/not-ready/dead (ie, it's from a failed * 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++; i++;
} }
} }
PG_CATCH(); PG_FINALLY();
{ {
/* Make sure list gets cleared on error exit */ /* Make sure list gets cleared on error exit */
ResetReindexPending(); ResetReindexPending();
PG_RE_THROW();
} }
PG_END_TRY(); PG_END_TRY();
ResetReindexPending();
/* /*
* Close rel, but continue to hold the lock. * Close rel, but continue to hold the lock.

View File

@ -2028,22 +2028,15 @@ asyncQueueReadAllNotifications(void)
snapshot); snapshot);
} while (!reachedStop); } while (!reachedStop);
} }
PG_CATCH(); PG_FINALLY();
{ {
/* Update shared state */ /* Update shared state */
LWLockAcquire(AsyncQueueLock, LW_SHARED); LWLockAcquire(AsyncQueueLock, LW_SHARED);
QUEUE_BACKEND_POS(MyBackendId) = pos; QUEUE_BACKEND_POS(MyBackendId) = pos;
LWLockRelease(AsyncQueueLock); LWLockRelease(AsyncQueueLock);
PG_RE_THROW();
} }
PG_END_TRY(); PG_END_TRY();
/* Update shared state */
LWLockAcquire(AsyncQueueLock, LW_SHARED);
QUEUE_BACKEND_POS(MyBackendId) = pos;
LWLockRelease(AsyncQueueLock);
/* Done with snapshot */ /* Done with snapshot */
UnregisterSnapshot(snapshot); UnregisterSnapshot(snapshot);
} }

View File

@ -1916,13 +1916,11 @@ BeginCopyTo(ParseState *pstate,
{ {
cstate->copy_file = AllocateFile(cstate->filename, PG_BINARY_W); cstate->copy_file = AllocateFile(cstate->filename, PG_BINARY_W);
} }
PG_CATCH(); PG_FINALLY();
{ {
umask(oumask); umask(oumask);
PG_RE_THROW();
} }
PG_END_TRY(); PG_END_TRY();
umask(oumask);
if (cstate->copy_file == NULL) if (cstate->copy_file == NULL)
{ {
/* copy errno because ereport subfunctions might change it */ /* copy errno because ereport subfunctions might change it */

View File

@ -934,13 +934,11 @@ EventTriggerSQLDrop(Node *parsetree)
{ {
EventTriggerInvoke(runlist, &trigdata); EventTriggerInvoke(runlist, &trigdata);
} }
PG_CATCH(); PG_FINALLY();
{ {
currentEventTriggerState->in_sql_drop = false; currentEventTriggerState->in_sql_drop = false;
PG_RE_THROW();
} }
PG_END_TRY(); PG_END_TRY();
currentEventTriggerState->in_sql_drop = false;
/* Cleanup. */ /* Cleanup. */
list_free(runlist); list_free(runlist);
@ -1007,17 +1005,13 @@ EventTriggerTableRewrite(Node *parsetree, Oid tableOid, int reason)
{ {
EventTriggerInvoke(runlist, &trigdata); EventTriggerInvoke(runlist, &trigdata);
} }
PG_CATCH(); PG_FINALLY();
{ {
currentEventTriggerState->table_rewrite_oid = InvalidOid; currentEventTriggerState->table_rewrite_oid = InvalidOid;
currentEventTriggerState->table_rewrite_reason = 0; currentEventTriggerState->table_rewrite_reason = 0;
PG_RE_THROW();
} }
PG_END_TRY(); PG_END_TRY();
currentEventTriggerState->table_rewrite_oid = InvalidOid;
currentEventTriggerState->table_rewrite_reason = 0;
/* Cleanup. */ /* Cleanup. */
list_free(runlist); list_free(runlist);

View File

@ -942,17 +942,13 @@ execute_extension_script(Oid extensionOid, ExtensionControlFile *control,
execute_sql_string(c_sql); execute_sql_string(c_sql);
} }
PG_CATCH(); PG_FINALLY();
{ {
creating_extension = false; creating_extension = false;
CurrentExtensionObject = InvalidOid; CurrentExtensionObject = InvalidOid;
PG_RE_THROW();
} }
PG_END_TRY(); PG_END_TRY();
creating_extension = false;
CurrentExtensionObject = InvalidOid;
/* /*
* Restore the GUC variables we set above. * Restore the GUC variables we set above.
*/ */

View File

@ -493,16 +493,11 @@ CreateSubscription(CreateSubscriptionStmt *stmt, bool isTopLevel)
slotname))); slotname)));
} }
} }
PG_CATCH(); PG_FINALLY();
{ {
/* Close the connection in case of failure. */
walrcv_disconnect(wrconn); walrcv_disconnect(wrconn);
PG_RE_THROW();
} }
PG_END_TRY(); PG_END_TRY();
/* And we are done with the remote side. */
walrcv_disconnect(wrconn);
} }
else else
ereport(WARNING, ereport(WARNING,
@ -1023,16 +1018,12 @@ DropSubscription(DropSubscriptionStmt *stmt, bool isTopLevel)
walrcv_clear_result(res); walrcv_clear_result(res);
} }
PG_CATCH(); PG_FINALLY();
{ {
/* Close the connection in case of failure */
walrcv_disconnect(wrconn); walrcv_disconnect(wrconn);
PG_RE_THROW();
} }
PG_END_TRY(); PG_END_TRY();
walrcv_disconnect(wrconn);
pfree(cmd.data); pfree(cmd.data);
table_close(rel, NoLock); table_close(rel, NoLock);

View File

@ -2431,13 +2431,11 @@ ExecCallTriggerFunc(TriggerData *trigdata,
{ {
result = FunctionCallInvoke(fcinfo); result = FunctionCallInvoke(fcinfo);
} }
PG_CATCH(); PG_FINALLY();
{ {
MyTriggerDepth--; MyTriggerDepth--;
PG_RE_THROW();
} }
PG_END_TRY(); PG_END_TRY();
MyTriggerDepth--;
pgstat_end_function_usage(&fcusage, true); pgstat_end_function_usage(&fcusage, true);

View File

@ -430,17 +430,13 @@ vacuum(List *relations, VacuumParams *params,
} }
} }
} }
PG_CATCH(); PG_FINALLY();
{ {
in_vacuum = false; in_vacuum = false;
VacuumCostActive = false; VacuumCostActive = false;
PG_RE_THROW();
} }
PG_END_TRY(); PG_END_TRY();
in_vacuum = false;
VacuumCostActive = false;
/* /*
* Finish up processing. * Finish up processing.
*/ */

View File

@ -503,13 +503,11 @@ be_lo_export(PG_FUNCTION_ARGS)
fd = OpenTransientFilePerm(fnamebuf, O_CREAT | O_WRONLY | O_TRUNC | PG_BINARY, fd = OpenTransientFilePerm(fnamebuf, O_CREAT | O_WRONLY | O_TRUNC | PG_BINARY,
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
} }
PG_CATCH(); PG_FINALLY();
{ {
umask(oumask); umask(oumask);
PG_RE_THROW();
} }
PG_END_TRY(); PG_END_TRY();
umask(oumask);
if (fd < 0) if (fd < 0)
ereport(ERROR, ereport(ERROR,
(errcode_for_file_access(), (errcode_for_file_access(),

View File

@ -1514,13 +1514,11 @@ ProcessUtilitySlow(ParseState *pstate,
address = ExecRefreshMatView((RefreshMatViewStmt *) parsetree, address = ExecRefreshMatView((RefreshMatViewStmt *) parsetree,
queryString, params, completionTag); queryString, params, completionTag);
} }
PG_CATCH(); PG_FINALLY();
{ {
EventTriggerUndoInhibitCommandCollection(); EventTriggerUndoInhibitCommandCollection();
PG_RE_THROW();
} }
PG_END_TRY(); PG_END_TRY();
EventTriggerUndoInhibitCommandCollection();
break; break;
case T_CreateTrigStmt: case T_CreateTrigStmt:
@ -1716,16 +1714,12 @@ ProcessUtilitySlow(ParseState *pstate,
EventTriggerDDLCommandEnd(parsetree); EventTriggerDDLCommandEnd(parsetree);
} }
} }
PG_CATCH(); PG_FINALLY();
{ {
if (needCleanup) if (needCleanup)
EventTriggerEndCompleteQuery(); EventTriggerEndCompleteQuery();
PG_RE_THROW();
} }
PG_END_TRY(); PG_END_TRY();
if (needCleanup)
EventTriggerEndCompleteQuery();
} }
/* /*

View File

@ -1193,13 +1193,11 @@ xml_pstrdup_and_free(xmlChar *str)
{ {
result = pstrdup((char *) str); result = pstrdup((char *) str);
} }
PG_CATCH(); PG_FINALLY();
{ {
xmlFree(str); xmlFree(str);
PG_RE_THROW();
} }
PG_END_TRY(); PG_END_TRY();
xmlFree(str);
} }
else else
result = NULL; result = NULL;
@ -3866,19 +3864,14 @@ xml_xmlnodetoxmltype(xmlNodePtr cur, PgXmlErrorContext *xmlerrcxt)
result = xmlBuffer_to_xmltype(buf); result = xmlBuffer_to_xmltype(buf);
} }
PG_CATCH(); PG_FINALLY()
{ {
if (nodefree) if (nodefree)
nodefree(cur_copy); nodefree(cur_copy);
if (buf) if (buf)
xmlBufferFree(buf); xmlBufferFree(buf);
PG_RE_THROW();
} }
PG_END_TRY(); PG_END_TRY();
if (nodefree)
nodefree(cur_copy);
xmlBufferFree(buf);
} }
else else
{ {
@ -3893,13 +3886,11 @@ xml_xmlnodetoxmltype(xmlNodePtr cur, PgXmlErrorContext *xmlerrcxt)
result = (xmltype *) cstring_to_text(escaped); result = (xmltype *) cstring_to_text(escaped);
pfree(escaped); pfree(escaped);
} }
PG_CATCH(); PG_FINALLY();
{ {
xmlFree(str); xmlFree(str);
PG_RE_THROW();
} }
PG_END_TRY(); PG_END_TRY();
xmlFree(str);
} }
return result; return result;
@ -4734,16 +4725,13 @@ XmlTableGetValue(TableFuncScanState *state, int colnum,
state->typioparams[colnum], state->typioparams[colnum],
typmod); typmod);
} }
PG_CATCH(); PG_FINALLY();
{ {
if (xpathobj != NULL) if (xpathobj != NULL)
xmlXPathFreeObject(xpathobj); xmlXPathFreeObject(xpathobj);
PG_RE_THROW();
} }
PG_END_TRY(); PG_END_TRY();
xmlXPathFreeObject(xpathobj);
return result; return result;
#else #else
NO_XML_SUPPORT(); NO_XML_SUPPORT();

View File

@ -277,6 +277,25 @@ extern PGDLLIMPORT ErrorContextCallback *error_context_stack;
* (sub)transaction abort. Failure to do so may leave the system in an * (sub)transaction abort. Failure to do so may leave the system in an
* inconsistent state for further processing. * 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) * Note: while the system will correctly propagate any new ereport(ERROR)
* occurring in the recovery section, there is a small limit on the number * 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 * 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() \ #define PG_TRY() \
do { \ do { \
sigjmp_buf *save_exception_stack = PG_exception_stack; \ sigjmp_buf *_save_exception_stack = PG_exception_stack; \
ErrorContextCallback *save_context_stack = error_context_stack; \ ErrorContextCallback *_save_context_stack = error_context_stack; \
sigjmp_buf local_sigjmp_buf; \ sigjmp_buf _local_sigjmp_buf; \
if (sigsetjmp(local_sigjmp_buf, 0) == 0) \ 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() \ #define PG_CATCH() \
} \ } \
else \ else \
{ \ { \
PG_exception_stack = save_exception_stack; \ PG_exception_stack = _save_exception_stack; \
error_context_stack = save_context_stack error_context_stack = _save_context_stack
#define PG_FINALLY() \
} \
else \
_do_rethrow = true; \
{
#define PG_END_TRY() \ #define PG_END_TRY() \
} \ } \
PG_exception_stack = save_exception_stack; \ PG_exception_stack = _save_exception_stack; \
error_context_stack = save_context_stack; \ error_context_stack = _save_context_stack; \
if (_do_rethrow) \
PG_RE_THROW(); \
} while (0) } while (0)
/* /*

View File

@ -1862,20 +1862,15 @@ plperl_call_handler(PG_FUNCTION_ARGS)
else else
retval = plperl_func_handler(fcinfo); retval = plperl_func_handler(fcinfo);
} }
PG_CATCH(); PG_FINALLY();
{ {
current_call_data = save_call_data; current_call_data = save_call_data;
activate_interpreter(oldinterp); activate_interpreter(oldinterp);
if (this_call_data.prodesc) if (this_call_data.prodesc)
decrement_prodesc_refcount(this_call_data.prodesc); decrement_prodesc_refcount(this_call_data.prodesc);
PG_RE_THROW();
} }
PG_END_TRY(); 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; return retval;
} }
@ -1958,22 +1953,15 @@ plperl_inline_handler(PG_FUNCTION_ARGS)
if (SPI_finish() != SPI_OK_FINISH) if (SPI_finish() != SPI_OK_FINISH)
elog(ERROR, "SPI_finish() failed"); elog(ERROR, "SPI_finish() failed");
} }
PG_CATCH(); PG_FINALLY();
{ {
if (desc.reference) if (desc.reference)
SvREFCNT_dec_current(desc.reference); SvREFCNT_dec_current(desc.reference);
current_call_data = save_call_data; current_call_data = save_call_data;
activate_interpreter(oldinterp); activate_interpreter(oldinterp);
PG_RE_THROW();
} }
PG_END_TRY(); 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; error_context_stack = pl_error_context.previous;
PG_RETURN_VOID(); PG_RETURN_VOID();

View File

@ -264,19 +264,14 @@ plpgsql_call_handler(PG_FUNCTION_ARGS)
else else
retval = plpgsql_exec_function(func, fcinfo, NULL, !nonatomic); 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->use_count--;
func->cur_estate = save_cur_estate; func->cur_estate = save_cur_estate;
PG_RE_THROW();
} }
PG_END_TRY(); PG_END_TRY();
func->use_count--;
func->cur_estate = save_cur_estate;
/* /*
* Disconnect from SPI manager * Disconnect from SPI manager
*/ */

View File

@ -228,13 +228,11 @@ PLy_cursor_plan(PyObject *ob, PyObject *args)
plan->values[j] = PLy_output_convert(arg, elem, &isnull); plan->values[j] = PLy_output_convert(arg, elem, &isnull);
nulls[j] = isnull ? 'n' : ' '; nulls[j] = isnull ? 'n' : ' ';
} }
PG_CATCH(); PG_FINALLY();
{ {
Py_DECREF(elem); Py_DECREF(elem);
PG_RE_THROW();
} }
PG_END_TRY(); PG_END_TRY();
Py_DECREF(elem);
} }
portal = SPI_cursor_open(NULL, plan->plan, plan->values, nulls, portal = SPI_cursor_open(NULL, plan->plan, plan->values, nulls,

View File

@ -141,7 +141,7 @@ PLy_elog_impl(int elevel, const char *fmt,...)
(constraint_name) ? err_generic_string(PG_DIAG_CONSTRAINT_NAME, (constraint_name) ? err_generic_string(PG_DIAG_CONSTRAINT_NAME,
constraint_name) : 0)); constraint_name) : 0));
} }
PG_CATCH(); PG_FINALLY();
{ {
if (fmt) if (fmt)
pfree(emsg.data); pfree(emsg.data);
@ -151,19 +151,8 @@ PLy_elog_impl(int elevel, const char *fmt,...)
pfree(tbmsg); pfree(tbmsg);
Py_XDECREF(exc); Py_XDECREF(exc);
Py_XDECREF(val); Py_XDECREF(val);
PG_RE_THROW();
} }
PG_END_TRY(); PG_END_TRY();
if (fmt)
pfree(emsg.data);
if (xmsg)
pfree(xmsg);
if (tbmsg)
pfree(tbmsg);
Py_XDECREF(exc);
Py_XDECREF(val);
} }
/* /*

View File

@ -403,18 +403,13 @@ PLy_exec_trigger(FunctionCallInfo fcinfo, PLyProcedure *proc)
} }
} }
} }
PG_CATCH(); PG_FINALLY();
{ {
Py_XDECREF(plargs); Py_XDECREF(plargs);
Py_XDECREF(plrv); Py_XDECREF(plrv);
PG_RE_THROW();
} }
PG_END_TRY(); PG_END_TRY();
Py_DECREF(plargs);
Py_DECREF(plrv);
return rv; return rv;
} }
@ -1052,15 +1047,12 @@ PLy_procedure_call(PLyProcedure *proc, const char *kargs, PyObject *vargs)
*/ */
Assert(list_length(explicit_subtransactions) >= save_subxact_level); Assert(list_length(explicit_subtransactions) >= save_subxact_level);
} }
PG_CATCH(); PG_FINALLY();
{ {
PLy_abort_open_subtransactions(save_subxact_level); PLy_abort_open_subtransactions(save_subxact_level);
PG_RE_THROW();
} }
PG_END_TRY(); PG_END_TRY();
PLy_abort_open_subtransactions(save_subxact_level);
/* If the Python code returned an error, propagate it */ /* If the Python code returned an error, propagate it */
if (rv == NULL) if (rv == NULL)
PLy_elog(ERROR, NULL); PLy_elog(ERROR, NULL);

View File

@ -249,13 +249,11 @@ PLy_spi_execute_plan(PyObject *ob, PyObject *list, long limit)
plan->values[j] = PLy_output_convert(arg, elem, &isnull); plan->values[j] = PLy_output_convert(arg, elem, &isnull);
nulls[j] = isnull ? 'n' : ' '; nulls[j] = isnull ? 'n' : ' ';
} }
PG_CATCH(); PG_FINALLY();
{ {
Py_DECREF(elem); Py_DECREF(elem);
PG_RE_THROW();
} }
PG_END_TRY(); PG_END_TRY();
Py_DECREF(elem);
} }
rv = SPI_execute_plan(plan->plan, plan->values, nulls, rv = SPI_execute_plan(plan->plan, plan->values, nulls,

View File

@ -925,15 +925,12 @@ PLyObject_ToBytea(PLyObToDatum *arg, PyObject *plrv,
memcpy(VARDATA(result), plrv_sc, len); memcpy(VARDATA(result), plrv_sc, len);
rv = PointerGetDatum(result); rv = PointerGetDatum(result);
} }
PG_CATCH(); PG_FINALLY();
{ {
Py_XDECREF(plrv_so); Py_XDECREF(plrv_so);
PG_RE_THROW();
} }
PG_END_TRY(); PG_END_TRY();
Py_XDECREF(plrv_so);
return rv; return rv;
} }

View File

@ -765,9 +765,10 @@ pltcl_handler(PG_FUNCTION_ARGS, bool pltrusted)
retval = pltcl_func_handler(fcinfo, &current_call_state, 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 */ /* 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; pltcl_current_call_state = save_call_state;
if (current_call_state.prodesc != NULL) 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) if (--current_call_state.prodesc->fn_refcount == 0)
MemoryContextDelete(current_call_state.prodesc->fn_cxt); MemoryContextDelete(current_call_state.prodesc->fn_cxt);
} }
PG_RE_THROW();
} }
PG_END_TRY(); 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; return retval;
} }