aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands/explain.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/commands/explain.c')
-rw-r--r--src/backend/commands/explain.c96
1 files changed, 68 insertions, 28 deletions
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 608ebf93ce8..39e8073f55b 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994-5, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.163 2007/05/04 21:29:52 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.164 2007/05/25 17:54:24 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -33,6 +33,12 @@
#include "utils/tuplesort.h"
+/* Hook for plugins to get control in ExplainOneQuery() */
+ExplainOneQuery_hook_type ExplainOneQuery_hook = NULL;
+/* Hook for plugins to get control in explain_get_index_name() */
+explain_get_index_name_hook_type explain_get_index_name_hook = NULL;
+
+
typedef struct ExplainState
{
/* options */
@@ -61,6 +67,8 @@ static void show_sort_keys(Plan *sortplan, int nkeys, AttrNumber *keycols,
StringInfo str, int indent, ExplainState *es);
static void show_sort_info(SortState *sortstate,
StringInfo str, int indent, ExplainState *es);
+static const char *explain_get_index_name(Oid indexId);
+
/*
* ExplainQuery -
@@ -140,9 +148,6 @@ static void
ExplainOneQuery(Query *query, ExplainStmt *stmt, const char *queryString,
ParamListInfo params, TupOutputState *tstate)
{
- PlannedStmt *plan;
- QueryDesc *queryDesc;
-
/* planner will not cope with utility statements */
if (query->commandType == CMD_UTILITY)
{
@@ -151,25 +156,19 @@ ExplainOneQuery(Query *query, ExplainStmt *stmt, const char *queryString,
return;
}
- /* plan the query */
- plan = planner(query, 0, params);
-
- /*
- * Update snapshot command ID to ensure this query sees results of any
- * previously executed queries. (It's a bit cheesy to modify
- * ActiveSnapshot without making a copy, but for the limited ways in which
- * EXPLAIN can be invoked, I think it's OK, because the active snapshot
- * shouldn't be shared with anything else anyway.)
- */
- ActiveSnapshot->curcid = GetCurrentCommandId();
+ /* if an advisor plugin is present, let it manage things */
+ if (ExplainOneQuery_hook)
+ (*ExplainOneQuery_hook) (query, stmt, queryString, params, tstate);
+ else
+ {
+ PlannedStmt *plan;
- /* Create a QueryDesc requesting no output */
- queryDesc = CreateQueryDesc(plan,
- ActiveSnapshot, InvalidSnapshot,
- None_Receiver, params,
- stmt->analyze);
+ /* plan the query */
+ plan = planner(query, 0, params);
- ExplainOnePlan(queryDesc, stmt, tstate);
+ /* run it (if needed) and produce output */
+ ExplainOnePlan(plan, params, stmt, tstate);
+ }
}
/*
@@ -210,20 +209,35 @@ ExplainOneUtility(Node *utilityStmt, ExplainStmt *stmt,
* not running the query. No cursor will be created, however.
*
* This is exported because it's called back from prepare.c in the
- * EXPLAIN EXECUTE case
- *
- * Note: the passed-in QueryDesc is freed when we're done with it
+ * EXPLAIN EXECUTE case, and because an index advisor plugin would need
+ * to call it.
*/
void
-ExplainOnePlan(QueryDesc *queryDesc, ExplainStmt *stmt,
- TupOutputState *tstate)
+ExplainOnePlan(PlannedStmt *plannedstmt, ParamListInfo params,
+ ExplainStmt *stmt, TupOutputState *tstate)
{
+ QueryDesc *queryDesc;
instr_time starttime;
double totaltime = 0;
ExplainState *es;
StringInfoData buf;
int eflags;
+ /*
+ * Update snapshot command ID to ensure this query sees results of any
+ * previously executed queries. (It's a bit cheesy to modify
+ * ActiveSnapshot without making a copy, but for the limited ways in which
+ * EXPLAIN can be invoked, I think it's OK, because the active snapshot
+ * shouldn't be shared with anything else anyway.)
+ */
+ ActiveSnapshot->curcid = GetCurrentCommandId();
+
+ /* Create a QueryDesc requesting no output */
+ queryDesc = CreateQueryDesc(plannedstmt,
+ ActiveSnapshot, InvalidSnapshot,
+ None_Receiver, params,
+ stmt->analyze);
+
INSTR_TIME_SET_CURRENT(starttime);
/* If analyzing, we need to cope with queued triggers */
@@ -592,7 +606,7 @@ explain_outNode(StringInfo str,
if (ScanDirectionIsBackward(((IndexScan *) plan)->indexorderdir))
appendStringInfoString(str, " Backward");
appendStringInfo(str, " using %s",
- quote_identifier(get_rel_name(((IndexScan *) plan)->indexid)));
+ explain_get_index_name(((IndexScan *) plan)->indexid));
/* FALL THRU */
case T_SeqScan:
case T_BitmapHeapScan:
@@ -618,7 +632,7 @@ explain_outNode(StringInfo str,
break;
case T_BitmapIndexScan:
appendStringInfo(str, " on %s",
- quote_identifier(get_rel_name(((BitmapIndexScan *) plan)->indexid)));
+ explain_get_index_name(((BitmapIndexScan *) plan)->indexid));
break;
case T_SubqueryScan:
if (((Scan *) plan)->scanrelid > 0)
@@ -1150,3 +1164,29 @@ show_sort_info(SortState *sortstate,
pfree(sortinfo);
}
}
+
+/*
+ * Fetch the name of an index in an EXPLAIN
+ *
+ * We allow plugins to get control here so that plans involving hypothetical
+ * indexes can be explained.
+ */
+static const char *
+explain_get_index_name(Oid indexId)
+{
+ const char *result;
+
+ if (explain_get_index_name_hook)
+ result = (*explain_get_index_name_hook) (indexId);
+ else
+ result = NULL;
+ if (result == NULL)
+ {
+ /* default behavior: look in the catalogs and quote it */
+ result = get_rel_name(indexId);
+ if (result == NULL)
+ elog(ERROR, "cache lookup failed for index %u", indexId);
+ result = quote_identifier(result);
+ }
+ return result;
+}