diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index 35c7f75..94d8557 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -14380,6 +14380,9 @@ SELECT set_config('log_statement_stats', 'off', false); pg_cancel_backend + pg_explain_backend + + pg_reload_conf @@ -14422,6 +14425,16 @@ SELECT set_config('log_statement_stats', 'off', false); + pg_explain_backend(pid int) + + boolean + EXPLAIN a backend's current query. 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. + + + + pg_reload_conf() boolean diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index 9d5d829..19177b3 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -58,6 +58,8 @@ #include "utils/tqual.h" +bool run_dynamic_explain = false; + /* Hooks for plugins to get control in ExecutorStart/Run/Finish/End */ ExecutorStart_hook_type ExecutorStart_hook = NULL; ExecutorRun_hook_type ExecutorRun_hook = NULL; @@ -2383,3 +2385,21 @@ EvalPlanQualEnd(EPQState *epqstate) epqstate->planstate = NULL; epqstate->origslot = NULL; } + +void +SetDynamicExplain(void) +{ + run_dynamic_explain = true; +} + +void +ResetDynamicExplain(void) +{ + run_dynamic_explain = false; +} + +bool +WantDynamicExplain(void) +{ + return run_dynamic_explain; +} diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c index a6f77c1..943e98e 100644 --- a/src/backend/storage/ipc/procsignal.c +++ b/src/backend/storage/ipc/procsignal.c @@ -276,6 +276,9 @@ procsignal_sigusr1_handler(SIGNAL_ARGS) if (CheckProcSignal(PROCSIG_RECOVERY_CONFLICT_BUFFERPIN)) RecoveryConflictInterrupt(PROCSIG_RECOVERY_CONFLICT_BUFFERPIN); + if (CheckProcSignal(PROCSIG_DYNAMIC_EXPLAIN)) + DynamicExplainInterrupt(); + latch_sigusr1_handler(); errno = save_errno; diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 407c548..fefa13a 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -184,6 +184,8 @@ static bool RecoveryConflictPending = false; static bool RecoveryConflictRetryable = true; static ProcSignalReason RecoveryConflictReason; +static bool DynamicExplainRequest = false; + /* ---------------------------------------------------------------- * decls for routines only used in this file * ---------------------------------------------------------------- @@ -2677,6 +2679,17 @@ SigHupHandler(SIGNAL_ARGS) } /* + * DynamicExplainInterrupt: out-of-line portion of dynamic EXPLAIN + * handling following receipt of SIGUSR1. Designed to be similar to die() + * and StatementCancelHandler(). + */ +void +DynamicExplainInterrupt(void) +{ + DynamicExplainRequest = true; +} + +/* * RecoveryConflictInterrupt: out-of-line portion of recovery conflict * handling following receipt of SIGUSR1. Designed to be similar to die() * and StatementCancelHandler(). Called only by a normal user backend @@ -2937,6 +2950,12 @@ ProcessInterrupts(void) errmsg("canceling statement due to user request"))); } } + if (DynamicExplainRequest) + { + DynamicExplainRequest = false; + if (WantDynamicExplain()) + RunDynamicExplain(); + } /* If we get here, do nothing (probably, QueryCancelPending was reset) */ } diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c index a36d065..2bda28c 100644 --- a/src/backend/utils/adt/misc.c +++ b/src/backend/utils/adt/misc.c @@ -156,6 +156,20 @@ pg_cancel_backend(PG_FUNCTION_ARGS) } /* + * Signal to EXPLAIN a backend process. This is allowed if you are superuser or + * have the same role as the process being canceled. + */ +Datum +pg_explain_backend(PG_FUNCTION_ARGS) +{ + /* XXX Add in tests for same user or superuser */ + + SendProcSignal(PG_GETARG_INT32(0), PROCSIG_DYNAMIC_EXPLAIN, InvalidBackendId); + + PG_RETURN_BOOL(true); +} + +/* * Signal to terminate a backend process. This is allowed if you are superuser * or have the same role as the process being terminated. */ diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index 010605d..901d9aa 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -2945,6 +2945,8 @@ DESCR("is schema another session's temp schema?"); DATA(insert OID = 2171 ( pg_cancel_backend PGNSP PGUID 12 1 0 0 0 f f f f t f v 1 0 16 "23" _null_ _null_ _null_ _null_ pg_cancel_backend _null_ _null_ _null_ )); DESCR("cancel a server process' current query"); +DATA(insert OID = 2171 ( pg_explain_backend PGNSP PGUID 12 1 0 0 0 f f f f t f v 1 0 16 "23" _null_ _null_ _null_ _null_ pg_explain_backend _null_ _null_ _null_ )); +DESCR("EXPLAIN a server process' current query"); DATA(insert OID = 2096 ( pg_terminate_backend PGNSP PGUID 12 1 0 0 0 f f f f t f v 1 0 16 "23" _null_ _null_ _null_ _null_ pg_terminate_backend _null_ _null_ _null_ )); DESCR("terminate a server process"); DATA(insert OID = 2172 ( pg_start_backup PGNSP PGUID 12 1 0 0 0 f f f f t f v 2 0 25 "25 16" _null_ _null_ _null_ _null_ pg_start_backup _null_ _null_ _null_ )); diff --git a/src/include/storage/procsignal.h b/src/include/storage/procsignal.h index 0f4b0cf..fa7898c 100644 --- a/src/include/storage/procsignal.h +++ b/src/include/storage/procsignal.h @@ -40,6 +40,8 @@ typedef enum PROCSIG_RECOVERY_CONFLICT_BUFFERPIN, PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK, + PROCSIG_DYNAMIC_EXPLAIN, + NUM_PROCSIGNALS /* Must be last! */ } ProcSignalReason; diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index 61d6aef..f42c4fe 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -473,6 +473,7 @@ extern Datum pg_ls_dir(PG_FUNCTION_ARGS); extern Datum current_database(PG_FUNCTION_ARGS); extern Datum current_query(PG_FUNCTION_ARGS); extern Datum pg_cancel_backend(PG_FUNCTION_ARGS); +extern Datum pg_explain_backend(PG_FUNCTION_ARGS); extern Datum pg_terminate_backend(PG_FUNCTION_ARGS); extern Datum pg_reload_conf(PG_FUNCTION_ARGS); extern Datum pg_tablespace_databases(PG_FUNCTION_ARGS);