Fix documentation about DROP DATABASE FORCE process termination rights.

Specifically, it terminates a background worker even if the caller
couldn't terminate the background worker with pg_terminate_backend().
Commit 3a9b18b309 neglected to update
this.  Back-patch to v13, which introduced DROP DATABASE FORCE.

Reviewed by Amit Kapila.  Reported by Kirill Reshke.

Discussion: https://postgr.es/m/20240429212756.60.nmisch@google.com
This commit is contained in:
Noah Misch 2024-05-16 14:11:00 -07:00
parent a3e6c6f929
commit 372700cf30
2 changed files with 21 additions and 16 deletions

View File

@ -79,12 +79,14 @@ DROP DATABASE [ IF EXISTS ] <replaceable class="parameter">name</replaceable> [
It doesn't terminate if prepared transactions, active logical replication It doesn't terminate if prepared transactions, active logical replication
slots or subscriptions are present in the target database. slots or subscriptions are present in the target database.
</para> </para>
<!-- not mentioning exception for autovacuum workers, since those are an
implementation detail and the exception is not specific to FORCE -->
<para> <para>
This will fail if the current user has no permissions to terminate other This terminates background worker connections and connections that the
connections. Required permissions are the same as with current user has permission to terminate
<literal>pg_terminate_backend</literal>, described in with <function>pg_terminate_backend</function>, described in
<xref linkend="functions-admin-signal"/>. This will also fail if we <xref linkend="functions-admin-signal"/>. If connections would remain,
are not able to terminate connections. this command will fail.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>

View File

@ -3808,8 +3808,8 @@ CountOtherDBBackends(Oid databaseId, int *nbackends, int *nprepared)
* The current backend is always ignored; it is caller's responsibility to * The current backend is always ignored; it is caller's responsibility to
* check whether the current backend uses the given DB, if it's important. * check whether the current backend uses the given DB, if it's important.
* *
* It doesn't allow to terminate the connections even if there is a one * If the target database has a prepared transaction or permissions checks
* backend with the prepared transaction in the target database. * fail for a connection, this fails without terminating anything.
*/ */
void void
TerminateOtherDBBackends(Oid databaseId) TerminateOtherDBBackends(Oid databaseId)
@ -3854,14 +3854,19 @@ TerminateOtherDBBackends(Oid databaseId)
ListCell *lc; ListCell *lc;
/* /*
* Check whether we have the necessary rights to terminate other * Permissions checks relax the pg_terminate_backend checks in two
* sessions. We don't terminate any session until we ensure that we * ways, both by omitting the !OidIsValid(proc->roleId) check:
* have rights on all the sessions to be terminated. These checks are
* the same as we do in pg_terminate_backend.
* *
* In this case we don't raise some warnings - like "PID %d is not a * - Accept terminating autovacuum workers, since DROP DATABASE
* PostgreSQL server process", because for us already finished session * without FORCE terminates them.
* is not a problem. *
* - Accept terminating bgworkers. For bgworker authors, it's
* convenient to be able to recommend FORCE if a worker is blocking
* DROP DATABASE unexpectedly.
*
* Unlike pg_terminate_backend, we don't raise some warnings - like
* "PID %d is not a PostgreSQL server process", because for us already
* finished session is not a problem.
*/ */
foreach(lc, pids) foreach(lc, pids)
{ {
@ -3870,7 +3875,6 @@ TerminateOtherDBBackends(Oid databaseId)
if (proc != NULL) if (proc != NULL)
{ {
/* Only allow superusers to signal superuser-owned backends. */
if (superuser_arg(proc->roleId) && !superuser()) if (superuser_arg(proc->roleId) && !superuser())
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
@ -3878,7 +3882,6 @@ TerminateOtherDBBackends(Oid databaseId)
errdetail("Only roles with the %s attribute may terminate processes of roles with the %s attribute.", errdetail("Only roles with the %s attribute may terminate processes of roles with the %s attribute.",
"SUPERUSER", "SUPERUSER"))); "SUPERUSER", "SUPERUSER")));
/* Users can signal backends they have role membership in. */
if (!has_privs_of_role(GetUserId(), proc->roleId) && if (!has_privs_of_role(GetUserId(), proc->roleId) &&
!has_privs_of_role(GetUserId(), ROLE_PG_SIGNAL_BACKEND)) !has_privs_of_role(GetUserId(), ROLE_PG_SIGNAL_BACKEND))
ereport(ERROR, ereport(ERROR,