From 43b6af42a90d96919a22c035d897cba2fbe46561 Mon Sep 17 00:00:00 2001
From: Daniel Farina <daniel@heroku.com>
Date: Wed, 28 Mar 2012 23:54:50 -0700
Subject: [PATCH] Extend same-role backend management to pg_terminate_backend

This makes it more similar to pg_cancel_backend, except it gives users
the ability to close runaway connections entirely.

Signed-off-by: Daniel Farina <daniel@heroku.com>
---
 doc/src/sgml/func.sgml              |   10 +++++-----
 doc/src/sgml/high-availability.sgml |   16 +++++++++-------
 src/backend/utils/adt/misc.c        |   12 +++++++-----
 3 files changed, 21 insertions(+), 17 deletions(-)

diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 34fea16..1a7b8ec 100644
*** a/doc/src/sgml/func.sgml
--- b/doc/src/sgml/func.sgml
***************
*** 14403,14409 **** SELECT set_config('log_statement_stats', 'off', false);
          <literal><function>pg_terminate_backend(<parameter>pid</parameter> <type>int</>)</function></literal>
          </entry>
         <entry><type>boolean</type></entry>
!        <entry>Terminate a backend</entry>
        </row>
       </tbody>
      </tgroup>
--- 14403,14413 ----
          <literal><function>pg_terminate_backend(<parameter>pid</parameter> <type>int</>)</function></literal>
          </entry>
         <entry><type>boolean</type></entry>
!        <entry>Terminate a backend.  You can execute this against
!         another backend that has exactly the same role as the user
!         calling the function.  In all other cases, you must be a
!         superuser.
!        </entry>
        </row>
       </tbody>
      </tgroup>
***************
*** 14424,14433 **** SELECT set_config('log_statement_stats', 'off', false);
      <command>postgres</command> processes on the server (using
      <application>ps</> on Unix or the <application>Task
      Manager</> on <productname>Windows</>).
-     For the less restrictive <function>pg_cancel_backend</>, the role of an
-     active backend can be found from
-     the <structfield>usename</structfield> column of the
-     <structname>pg_stat_activity</structname> view.
     </para>
  
     <para>
--- 14428,14433 ----
*** a/doc/src/sgml/high-availability.sgml
--- b/doc/src/sgml/high-availability.sgml
***************
*** 1969,1981 **** LOG:  database system is ready to accept read only connections
     </para>
  
     <para>
!     <function>pg_cancel_backend()</> will work on user backends, but not the
!     Startup process, which performs recovery. <structname>pg_stat_activity</structname> does not
!     show an entry for the Startup process, nor do recovering transactions
!     show as active. As a result, <structname>pg_prepared_xacts</structname> is always empty during
!     recovery. If you wish to resolve in-doubt prepared transactions,
!     view <literal>pg_prepared_xacts</> on the primary and issue commands to
!     resolve transactions there.
     </para>
  
     <para>
--- 1969,1983 ----
     </para>
  
     <para>
!     <function>pg_cancel_backend()</>
!     and <function>pg_terminate_backend()</> will work on user backends,
!     but not the Startup process, which performs
!     recovery. <structname>pg_stat_activity</structname> does not show an
!     entry for the Startup process, nor do recovering transactions show
!     as active. As a result, <structname>pg_prepared_xacts</structname>
!     is always empty during recovery. If you wish to resolve in-doubt
!     prepared transactions, view <literal>pg_prepared_xacts</> on the
!     primary and issue commands to resolve transactions there.
     </para>
  
     <para>
*** a/src/backend/utils/adt/misc.c
--- b/src/backend/utils/adt/misc.c
***************
*** 162,179 **** pg_cancel_backend(PG_FUNCTION_ARGS)
  }
  
  /*
!  * Signal to terminate a backend process.  Only allowed by superuser.
   */
  Datum
  pg_terminate_backend(PG_FUNCTION_ARGS)
  {
! 	if (!superuser())
  		ereport(ERROR,
  				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! 			 errmsg("must be superuser to terminate other server processes"),
! 				 errhint("You can cancel your own processes with pg_cancel_backend().")));
  
! 	PG_RETURN_BOOL(pg_signal_backend(PG_GETARG_INT32(0), SIGTERM) == SIGNAL_BACKEND_SUCCESS);
  }
  
  /*
--- 162,181 ----
  }
  
  /*
!  * Signal to terminate a backend process.  This is allowed if you are superuser
!  * or have the same role as the process being terminated.
   */
  Datum
  pg_terminate_backend(PG_FUNCTION_ARGS)
  {
! 	int			r = pg_signal_backend(PG_GETARG_INT32(0), SIGTERM);
! 
! 	if (r == SIGNAL_BACKEND_NOPERMISSION)
  		ereport(ERROR,
  				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! 				 (errmsg("must be superuser or have the same role to terminate backends running in other server processes"))));
  
! 	PG_RETURN_BOOL(r == SIGNAL_BACKEND_SUCCESS);
  }
  
  /*