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 e6fc3b70df
commit 484b958737
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
slots or subscriptions are present in the target database.
</para>
<!-- not mentioning exception for autovacuum workers, since those are an
implementation detail and the exception is not specific to FORCE -->
<para>
This will fail if the current user has no permissions to terminate other
connections. Required permissions are the same as with
<literal>pg_terminate_backend</literal>, described in
<xref linkend="functions-admin-signal"/>. This will also fail if we
are not able to terminate connections.
This terminates background worker connections and connections that the
current user has permission to terminate
with <function>pg_terminate_backend</function>, described in
<xref linkend="functions-admin-signal"/>. If connections would remain,
this command will fail.
</para>
</listitem>
</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
* 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
* backend with the prepared transaction in the target database.
* If the target database has a prepared transaction or permissions checks
* fail for a connection, this fails without terminating anything.
*/
void
TerminateOtherDBBackends(Oid databaseId)
@ -3854,14 +3854,19 @@ TerminateOtherDBBackends(Oid databaseId)
ListCell *lc;
/*
* Check whether we have the necessary rights to terminate other
* sessions. We don't terminate any session until we ensure that we
* have rights on all the sessions to be terminated. These checks are
* the same as we do in pg_terminate_backend.
* Permissions checks relax the pg_terminate_backend checks in two
* ways, both by omitting the !OidIsValid(proc->roleId) check:
*
* In this case 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.
* - Accept terminating autovacuum workers, since DROP DATABASE
* without FORCE terminates them.
*
* - 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)
{
@ -3870,13 +3875,11 @@ TerminateOtherDBBackends(Oid databaseId)
if (proc != NULL)
{
/* Only allow superusers to signal superuser-owned backends. */
if (superuser_arg(proc->roleId) && !superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be a superuser to terminate superuser process")));
/* Users can signal backends they have role membership in. */
if (!has_privs_of_role(GetUserId(), proc->roleId) &&
!has_privs_of_role(GetUserId(), ROLE_PG_SIGNAL_BACKEND))
ereport(ERROR,