/* *-------------------------------------------------------------- * Async_UnlistenOnExit * * Clean up the pg_listener table at backend exit. * * This is executed if we have done any LISTENs in this backend. * It might not be necessary anymore, if the user UNLISTENed everything, * but we don't try to detect that case. * * Results: * XXX * * Side effects: * pg_listener is updated if necessary. * *-------------------------------------------------------------- */ static void Async_UnlistenOnExit(int code, Datum arg) { /* * We need to start/commit a transaction for the unlisten, but if there is * already an active transaction we had better abort that one first. * Otherwise we'd end up committing changes that probably ought to be * discarded. */ AbortOutOfAnyTransaction(); /* Now we can do the unlisten */ StartTransactionCommand(); Async_UnlistenAll(); CommitTransactionCommand(); }
/* * Async_Unlisten * * This is executed by the SQL unlisten command. */ void Async_Unlisten(const char *relname) { /* Handle specially the `unlisten "*"' command */ if ((!relname) || (*relname == '\0') || (strcmp(relname, "*") == 0)) { Async_UnlistenAll(); } else { if (Trace_notify) elog(DEBUG1, "Async_Unlisten(%s,%d)", relname, MyProcPid); queue_listen(LISTEN_UNLISTEN, relname); } }
/* *-------------------------------------------------------------- * Async_Unlisten * * This is executed by the SQL unlisten command. * * Remove the current backend from the list of listening backends * for the specified relation. * * Side effects: * pg_listener is updated. * *-------------------------------------------------------------- */ void Async_Unlisten(const char *relname) { Relation lRel; HeapScanDesc scan; HeapTuple tuple; /* Handle specially the `unlisten "*"' command */ if ((!relname) || (*relname == '\0') || (strcmp(relname, "*") == 0)) { Async_UnlistenAll(); return; } if (Trace_notify) elog(DEBUG1, "Async_Unlisten(%s,%d)", relname, MyProcPid); lRel = heap_open(ListenerRelationId, ExclusiveLock); scan = heap_beginscan(lRel, SnapshotNow, 0, NULL); while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) { Form_pg_listener listener = (Form_pg_listener) GETSTRUCT(tuple); if (listener->listenerpid == MyProcPid && strncmp(NameStr(listener->relname), relname, NAMEDATALEN) == 0) { /* Found the matching tuple, delete it */ simple_heap_delete(lRel, &tuple->t_self); /* * We assume there can be only one match, so no need to scan the * rest of the table */ break; } } heap_endscan(scan); heap_close(lRel, ExclusiveLock); /* * We do not complain about unlistening something not being listened; * should we? */ }
static void DiscardAll(bool isTopLevel) { /* * Disallow DISCARD ALL in a transaction block. This is arguably * inconsistent (we don't make a similar check in the command sequence * that DISCARD ALL is equivalent to), but the idea is to catch mistakes: * DISCARD ALL inside a transaction block would leave the transaction * still uncommitted. */ PreventTransactionChain(isTopLevel, "DISCARD ALL"); SetPGVariable("session_authorization", NIL, false); ResetAllOptions(); DropAllPreparedStatements(); PortalHashTableDeleteAll(); Async_UnlistenAll(); LockReleaseAll(USER_LOCKMETHOD, true); ResetPlanCache(); ResetTempTableNamespace(); }