7
7
* Portions Copyright (c) 1994-5, Regents of the University of California
8
8
*
9
9
* IDENTIFICATION
10
- * $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.163 2007/05/04 21:29:52 tgl Exp $
10
+ * $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.164 2007/05/25 17:54:24 tgl Exp $
11
11
*
12
12
*-------------------------------------------------------------------------
13
13
*/
33
33
#include "utils/tuplesort.h"
34
34
35
35
36
+ /* Hook for plugins to get control in ExplainOneQuery() */
37
+ ExplainOneQuery_hook_type ExplainOneQuery_hook = NULL ;
38
+ /* Hook for plugins to get control in explain_get_index_name() */
39
+ explain_get_index_name_hook_type explain_get_index_name_hook = NULL ;
40
+
41
+
36
42
typedef struct ExplainState
37
43
{
38
44
/* options */
@@ -61,6 +67,8 @@ static void show_sort_keys(Plan *sortplan, int nkeys, AttrNumber *keycols,
61
67
StringInfo str , int indent , ExplainState * es );
62
68
static void show_sort_info (SortState * sortstate ,
63
69
StringInfo str , int indent , ExplainState * es );
70
+ static const char * explain_get_index_name (Oid indexId );
71
+
64
72
65
73
/*
66
74
* ExplainQuery -
@@ -140,9 +148,6 @@ static void
140
148
ExplainOneQuery (Query * query , ExplainStmt * stmt , const char * queryString ,
141
149
ParamListInfo params , TupOutputState * tstate )
142
150
{
143
- PlannedStmt * plan ;
144
- QueryDesc * queryDesc ;
145
-
146
151
/* planner will not cope with utility statements */
147
152
if (query -> commandType == CMD_UTILITY )
148
153
{
@@ -151,25 +156,19 @@ ExplainOneQuery(Query *query, ExplainStmt *stmt, const char *queryString,
151
156
return ;
152
157
}
153
158
154
- /* plan the query */
155
- plan = planner (query , 0 , params );
156
-
157
- /*
158
- * Update snapshot command ID to ensure this query sees results of any
159
- * previously executed queries. (It's a bit cheesy to modify
160
- * ActiveSnapshot without making a copy, but for the limited ways in which
161
- * EXPLAIN can be invoked, I think it's OK, because the active snapshot
162
- * shouldn't be shared with anything else anyway.)
163
- */
164
- ActiveSnapshot -> curcid = GetCurrentCommandId ();
159
+ /* if an advisor plugin is present, let it manage things */
160
+ if (ExplainOneQuery_hook )
161
+ (* ExplainOneQuery_hook ) (query , stmt , queryString , params , tstate );
162
+ else
163
+ {
164
+ PlannedStmt * plan ;
165
165
166
- /* Create a QueryDesc requesting no output */
167
- queryDesc = CreateQueryDesc (plan ,
168
- ActiveSnapshot , InvalidSnapshot ,
169
- None_Receiver , params ,
170
- stmt -> analyze );
166
+ /* plan the query */
167
+ plan = planner (query , 0 , params );
171
168
172
- ExplainOnePlan (queryDesc , stmt , tstate );
169
+ /* run it (if needed) and produce output */
170
+ ExplainOnePlan (plan , params , stmt , tstate );
171
+ }
173
172
}
174
173
175
174
/*
@@ -210,20 +209,35 @@ ExplainOneUtility(Node *utilityStmt, ExplainStmt *stmt,
210
209
* not running the query. No cursor will be created, however.
211
210
*
212
211
* This is exported because it's called back from prepare.c in the
213
- * EXPLAIN EXECUTE case
214
- *
215
- * Note: the passed-in QueryDesc is freed when we're done with it
212
+ * EXPLAIN EXECUTE case, and because an index advisor plugin would need
213
+ * to call it.
216
214
*/
217
215
void
218
- ExplainOnePlan (QueryDesc * queryDesc , ExplainStmt * stmt ,
219
- TupOutputState * tstate )
216
+ ExplainOnePlan (PlannedStmt * plannedstmt , ParamListInfo params ,
217
+ ExplainStmt * stmt , TupOutputState * tstate )
220
218
{
219
+ QueryDesc * queryDesc ;
221
220
instr_time starttime ;
222
221
double totaltime = 0 ;
223
222
ExplainState * es ;
224
223
StringInfoData buf ;
225
224
int eflags ;
226
225
226
+ /*
227
+ * Update snapshot command ID to ensure this query sees results of any
228
+ * previously executed queries. (It's a bit cheesy to modify
229
+ * ActiveSnapshot without making a copy, but for the limited ways in which
230
+ * EXPLAIN can be invoked, I think it's OK, because the active snapshot
231
+ * shouldn't be shared with anything else anyway.)
232
+ */
233
+ ActiveSnapshot -> curcid = GetCurrentCommandId ();
234
+
235
+ /* Create a QueryDesc requesting no output */
236
+ queryDesc = CreateQueryDesc (plannedstmt ,
237
+ ActiveSnapshot , InvalidSnapshot ,
238
+ None_Receiver , params ,
239
+ stmt -> analyze );
240
+
227
241
INSTR_TIME_SET_CURRENT (starttime );
228
242
229
243
/* If analyzing, we need to cope with queued triggers */
@@ -592,7 +606,7 @@ explain_outNode(StringInfo str,
592
606
if (ScanDirectionIsBackward (((IndexScan * ) plan )-> indexorderdir ))
593
607
appendStringInfoString (str , " Backward" );
594
608
appendStringInfo (str , " using %s" ,
595
- quote_identifier ( get_rel_name ((( IndexScan * ) plan )-> indexid ) ));
609
+ explain_get_index_name ((( IndexScan * ) plan )-> indexid ));
596
610
/* FALL THRU */
597
611
case T_SeqScan :
598
612
case T_BitmapHeapScan :
@@ -618,7 +632,7 @@ explain_outNode(StringInfo str,
618
632
break ;
619
633
case T_BitmapIndexScan :
620
634
appendStringInfo (str , " on %s" ,
621
- quote_identifier ( get_rel_name ((( BitmapIndexScan * ) plan )-> indexid ) ));
635
+ explain_get_index_name ((( BitmapIndexScan * ) plan )-> indexid ));
622
636
break ;
623
637
case T_SubqueryScan :
624
638
if (((Scan * ) plan )-> scanrelid > 0 )
@@ -1150,3 +1164,29 @@ show_sort_info(SortState *sortstate,
1150
1164
pfree (sortinfo );
1151
1165
}
1152
1166
}
1167
+
1168
+ /*
1169
+ * Fetch the name of an index in an EXPLAIN
1170
+ *
1171
+ * We allow plugins to get control here so that plans involving hypothetical
1172
+ * indexes can be explained.
1173
+ */
1174
+ static const char *
1175
+ explain_get_index_name (Oid indexId )
1176
+ {
1177
+ const char * result ;
1178
+
1179
+ if (explain_get_index_name_hook )
1180
+ result = (* explain_get_index_name_hook ) (indexId );
1181
+ else
1182
+ result = NULL ;
1183
+ if (result == NULL )
1184
+ {
1185
+ /* default behavior: look in the catalogs and quote it */
1186
+ result = get_rel_name (indexId );
1187
+ if (result == NULL )
1188
+ elog (ERROR , "cache lookup failed for index %u" , indexId );
1189
+ result = quote_identifier (result );
1190
+ }
1191
+ return result ;
1192
+ }
0 commit comments