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);