explain.c 30.3 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * explain.c
4
 *	  Explain query execution plans
5
 *
6
 * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
B
Add:  
Bruce Momjian 已提交
7
 * Portions Copyright (c) 1994-5, Regents of the University of California
8
 *
9
 * IDENTIFICATION
B
Bruce Momjian 已提交
10
 *	  $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.166 2007/11/15 21:14:33 momjian Exp $
11
 *
12
 *-------------------------------------------------------------------------
13
 */
14
#include "postgres.h"
M
Marc G. Fournier 已提交
15

16
#include "access/xact.h"
17
#include "catalog/pg_constraint.h"
18
#include "catalog/pg_type.h"
19
#include "commands/explain.h"
20
#include "commands/prepare.h"
21
#include "commands/trigger.h"
22
#include "executor/instrument.h"
B
Bruce Momjian 已提交
23
#include "nodes/print.h"
24
#include "optimizer/clauses.h"
25
#include "optimizer/planner.h"
26
#include "optimizer/var.h"
B
Bruce Momjian 已提交
27
#include "parser/parsetree.h"
28
#include "rewrite/rewriteHandler.h"
29
#include "tcop/tcopprot.h"
30
#include "utils/builtins.h"
31
#include "utils/guc.h"
32
#include "utils/lsyscache.h"
33
#include "utils/tuplesort.h"
34

35

36 37
/* Hook for plugins to get control in ExplainOneQuery() */
ExplainOneQuery_hook_type ExplainOneQuery_hook = NULL;
B
Bruce Momjian 已提交
38

39 40 41 42
/* Hook for plugins to get control in explain_get_index_name() */
explain_get_index_name_hook_type explain_get_index_name_hook = NULL;


43 44 45
typedef struct ExplainState
{
	/* options */
46 47
	bool		printNodes;		/* do nodeToString() too */
	bool		printAnalyze;	/* print actual times */
48
	/* other states */
49
	PlannedStmt *pstmt;			/* top of plan */
50
	List	   *rtable;			/* range table */
51
} ExplainState;
52

53
static void ExplainOneQuery(Query *query, ExplainStmt *stmt,
B
Bruce Momjian 已提交
54 55
				const char *queryString,
				ParamListInfo params, TupOutputState *tstate);
56
static void report_triggers(ResultRelInfo *rInfo, bool show_relname,
B
Bruce Momjian 已提交
57
				StringInfo buf);
58
static double elapsed_time(instr_time *starttime);
59
static void explain_outNode(StringInfo str,
60
				Plan *plan, PlanState *planstate,
B
Bruce Momjian 已提交
61 62
				Plan *outer_plan,
				int indent, ExplainState *es);
63
static void show_scan_qual(List *qual, const char *qlabel,
64
			   int scanrelid, Plan *outer_plan, Plan *inner_plan,
B
Bruce Momjian 已提交
65
			   StringInfo str, int indent, ExplainState *es);
66
static void show_upper_qual(List *qual, const char *qlabel, Plan *plan,
B
Bruce Momjian 已提交
67
				StringInfo str, int indent, ExplainState *es);
68
static void show_sort_keys(Plan *sortplan, int nkeys, AttrNumber *keycols,
B
Bruce Momjian 已提交
69 70
			   const char *qlabel,
			   StringInfo str, int indent, ExplainState *es);
71 72
static void show_sort_info(SortState *sortstate,
			   StringInfo str, int indent, ExplainState *es);
73 74
static const char *explain_get_index_name(Oid indexId);

75 76 77

/*
 * ExplainQuery -
78
 *	  execute an EXPLAIN command
79 80
 */
void
81 82
ExplainQuery(ExplainStmt *stmt, const char *queryString,
			 ParamListInfo params, DestReceiver *dest)
83
{
84 85
	Oid		   *param_types;
	int			num_params;
86
	TupOutputState *tstate;
B
Bruce Momjian 已提交
87
	List	   *rewritten;
88
	ListCell   *l;
89

90 91 92
	/* Convert parameter type data to the form parser wants */
	getParamListTypes(params, &param_types, &num_params);

93
	/*
B
Bruce Momjian 已提交
94
	 * Run parse analysis and rewrite.	Note this also acquires sufficient
95 96
	 * locks on the source table(s).
	 *
B
Bruce Momjian 已提交
97 98 99 100 101
	 * Because the parser and planner tend to scribble on their input, we make
	 * a preliminary copy of the source querytree.	This prevents problems in
	 * the case that the EXPLAIN is in a portal or plpgsql function and is
	 * executed repeatedly.  (See also the same hack in DECLARE CURSOR and
	 * PREPARE.)  XXX FIXME someday.
102
	 */
103 104
	rewritten = pg_analyze_and_rewrite((Node *) copyObject(stmt->query),
									   queryString, param_types, num_params);
105

106
	/* prepare for projection of tuples */
107
	tstate = begin_tup_output_tupdesc(dest, ExplainResultDesc(stmt));
108

109
	if (rewritten == NIL)
110
	{
111 112
		/* In the case of an INSTEAD NOTHING, tell at least that */
		do_text_output_oneline(tstate, "Query rewrites to nothing");
113
	}
114
	else
B
Bruce Momjian 已提交
115
	{
116 117
		/* Explain every plan */
		foreach(l, rewritten)
118
		{
119 120
			ExplainOneQuery((Query *) lfirst(l), stmt,
							queryString, params, tstate);
121 122 123
			/* put a blank line between plans */
			if (lnext(l) != NULL)
				do_text_output_oneline(tstate, "");
124
		}
B
Bruce Momjian 已提交
125 126
	}

127
	end_tup_output(tstate);
B
Bruce Momjian 已提交
128 129
}

130 131 132 133 134 135 136 137 138 139 140 141
/*
 * ExplainResultDesc -
 *	  construct the result tupledesc for an EXPLAIN
 */
TupleDesc
ExplainResultDesc(ExplainStmt *stmt)
{
	TupleDesc	tupdesc;

	/* need a tuple descriptor representing a single TEXT column */
	tupdesc = CreateTemplateTupleDesc(1, false);
	TupleDescInitEntry(tupdesc, (AttrNumber) 1, "QUERY PLAN",
142
					   TEXTOID, -1, 0);
143 144 145
	return tupdesc;
}

B
Bruce Momjian 已提交
146 147
/*
 * ExplainOneQuery -
148
 *	  print out the execution plan for one Query
B
Bruce Momjian 已提交
149 150
 */
static void
151
ExplainOneQuery(Query *query, ExplainStmt *stmt, const char *queryString,
152
				ParamListInfo params, TupOutputState *tstate)
B
Bruce Momjian 已提交
153
{
154 155 156
	/* planner will not cope with utility statements */
	if (query->commandType == CMD_UTILITY)
	{
157 158 159
		ExplainOneUtility(query->utilityStmt, stmt,
						  queryString, params, tstate);
		return;
160 161
	}

162 163 164 165 166 167
	/* if an advisor plugin is present, let it manage things */
	if (ExplainOneQuery_hook)
		(*ExplainOneQuery_hook) (query, stmt, queryString, params, tstate);
	else
	{
		PlannedStmt *plan;
168

169 170
		/* plan the query */
		plan = planner(query, 0, params);
171

172 173 174
		/* run it (if needed) and produce output */
		ExplainOnePlan(plan, params, stmt, tstate);
	}
175 176
}

177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
/*
 * ExplainOneUtility -
 *	  print out the execution plan for one utility statement
 *	  (In general, utility statements don't have plans, but there are some
 *	  we treat as special cases)
 *
 * This is exported because it's called back from prepare.c in the
 * EXPLAIN EXECUTE case
 */
void
ExplainOneUtility(Node *utilityStmt, ExplainStmt *stmt,
				  const char *queryString, ParamListInfo params,
				  TupOutputState *tstate)
{
	if (utilityStmt == NULL)
		return;

194
	if (IsA(utilityStmt, ExecuteStmt))
195 196 197 198 199 200 201 202 203
		ExplainExecuteQuery((ExecuteStmt *) utilityStmt, stmt,
							queryString, params, tstate);
	else if (IsA(utilityStmt, NotifyStmt))
		do_text_output_oneline(tstate, "NOTIFY");
	else
		do_text_output_oneline(tstate,
							   "Utility statements have no plan structure");
}

204 205 206 207 208
/*
 * ExplainOnePlan -
 *		given a planned query, execute it if needed, and then print
 *		EXPLAIN output
 *
209 210 211 212 213
 * Since we ignore any DeclareCursorStmt that might be attached to the query,
 * if you say EXPLAIN ANALYZE DECLARE CURSOR then we'll actually run the
 * query.  This is different from pre-8.3 behavior but seems more useful than
 * not running the query.  No cursor will be created, however.
 *
214
 * This is exported because it's called back from prepare.c in the
215 216
 * EXPLAIN EXECUTE case, and because an index advisor plugin would need
 * to call it.
217 218
 */
void
B
Bruce Momjian 已提交
219
ExplainOnePlan(PlannedStmt * plannedstmt, ParamListInfo params,
220
			   ExplainStmt *stmt, TupOutputState *tstate)
221
{
222
	QueryDesc  *queryDesc;
B
Bruce Momjian 已提交
223
	instr_time	starttime;
224 225
	double		totaltime = 0;
	ExplainState *es;
226
	StringInfoData buf;
227
	int			eflags;
228

229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
	/*
	 * 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);

244
	INSTR_TIME_SET_CURRENT(starttime);
245

246 247 248 249
	/* If analyzing, we need to cope with queued triggers */
	if (stmt->analyze)
		AfterTriggerBeginQuery();

250 251 252 253 254 255
	/* Select execution options */
	if (stmt->analyze)
		eflags = 0;				/* default run-to-completion flags */
	else
		eflags = EXEC_FLAG_EXPLAIN_ONLY;

256
	/* call ExecutorStart to prepare the plan for execution */
257
	ExecutorStart(queryDesc, eflags);
258

259
	/* Execute the plan for statistics if asked for */
260
	if (stmt->analyze)
261
	{
262 263
		/* run the plan */
		ExecutorRun(queryDesc, ForwardScanDirection, 0L);
264

265 266
		/* We can't clean up 'till we're done printing the stats... */
		totaltime += elapsed_time(&starttime);
267 268
	}

269
	es = (ExplainState *) palloc0(sizeof(ExplainState));
B
Bruce Momjian 已提交
270

271 272
	es->printNodes = stmt->verbose;
	es->printAnalyze = stmt->analyze;
273
	es->pstmt = queryDesc->plannedstmt;
274
	es->rtable = queryDesc->plannedstmt->rtable;
275 276

	if (es->printNodes)
277
	{
278
		char	   *s;
279
		char	   *f;
280

281
		s = nodeToString(queryDesc->plannedstmt->planTree);
282 283
		if (s)
		{
284 285 286 287
			if (Explain_pretty_print)
				f = pretty_format_node_dump(s);
			else
				f = format_node_dump(s);
288
			pfree(s);
289 290
			do_text_output_multiline(tstate, f);
			pfree(f);
B
Bruce Momjian 已提交
291
			do_text_output_oneline(tstate, ""); /* separator line */
292 293
		}
	}
294

295
	initStringInfo(&buf);
296 297
	explain_outNode(&buf,
					queryDesc->plannedstmt->planTree, queryDesc->planstate,
298
					NULL, 0, es);
299 300

	/*
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315
	 * If we ran the command, run any AFTER triggers it queued.  (Note this
	 * will not include DEFERRED triggers; since those don't run until end of
	 * transaction, we can't measure them.)  Include into total runtime.
	 */
	if (stmt->analyze)
	{
		INSTR_TIME_SET_CURRENT(starttime);
		AfterTriggerEndQuery(queryDesc->estate);
		totaltime += elapsed_time(&starttime);
	}

	/* Print info about runtime of triggers */
	if (es->printAnalyze)
	{
		ResultRelInfo *rInfo;
316
		bool		show_relname;
B
Bruce Momjian 已提交
317
		int			numrels = queryDesc->estate->es_num_result_relations;
318
		List	   *targrels = queryDesc->estate->es_trig_target_relations;
B
Bruce Momjian 已提交
319
		int			nr;
320
		ListCell   *l;
321

322
		show_relname = (numrels > 1 || targrels != NIL);
323 324
		rInfo = queryDesc->estate->es_result_relations;
		for (nr = 0; nr < numrels; rInfo++, nr++)
325 326 327
			report_triggers(rInfo, show_relname, &buf);

		foreach(l, targrels)
328
		{
329 330
			rInfo = (ResultRelInfo *) lfirst(l);
			report_triggers(rInfo, show_relname, &buf);
331 332 333 334
		}
	}

	/*
B
Bruce Momjian 已提交
335 336
	 * Close down the query and free resources.  Include time for this in the
	 * total runtime (although it should be pretty minimal).
337
	 */
338
	INSTR_TIME_SET_CURRENT(starttime);
339

340
	ExecutorEnd(queryDesc);
341

342 343
	FreeQueryDesc(queryDesc);

344 345 346
	/* We need a CCI just in case query expanded to multiple plans */
	if (stmt->analyze)
		CommandCounterIncrement();
347 348 349

	totaltime += elapsed_time(&starttime);

350
	if (stmt->analyze)
351
		appendStringInfo(&buf, "Total runtime: %.3f ms\n",
352
						 1000.0 * totaltime);
353
	do_text_output_multiline(tstate, buf.data);
354

355
	pfree(buf.data);
B
Bruce Momjian 已提交
356
	pfree(es);
357 358
}

359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379
/*
 * report_triggers -
 *		report execution stats for a single relation's triggers
 */
static void
report_triggers(ResultRelInfo *rInfo, bool show_relname, StringInfo buf)
{
	int			nt;

	if (!rInfo->ri_TrigDesc || !rInfo->ri_TrigInstrument)
		return;
	for (nt = 0; nt < rInfo->ri_TrigDesc->numtriggers; nt++)
	{
		Trigger    *trig = rInfo->ri_TrigDesc->triggers + nt;
		Instrumentation *instr = rInfo->ri_TrigInstrument + nt;
		char	   *conname;

		/* Must clean up instrumentation state */
		InstrEndLoop(instr);

		/*
B
Bruce Momjian 已提交
380 381
		 * We ignore triggers that were never invoked; they likely aren't
		 * relevant to the current query type.
382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403
		 */
		if (instr->ntuples == 0)
			continue;

		if (OidIsValid(trig->tgconstraint) &&
			(conname = get_constraint_name(trig->tgconstraint)) != NULL)
		{
			appendStringInfo(buf, "Trigger for constraint %s", conname);
			pfree(conname);
		}
		else
			appendStringInfo(buf, "Trigger %s", trig->tgname);

		if (show_relname)
			appendStringInfo(buf, " on %s",
							 RelationGetRelationName(rInfo->ri_RelationDesc));

		appendStringInfo(buf, ": time=%.3f calls=%.0f\n",
						 1000.0 * instr->total, instr->ntuples);
	}
}

404
/* Compute elapsed time in seconds since given timestamp */
405
static double
406
elapsed_time(instr_time *starttime)
407
{
B
Bruce Momjian 已提交
408
	instr_time	endtime;
409

410
	INSTR_TIME_SET_CURRENT(endtime);
411

412
#ifndef WIN32
413 414 415 416 417 418 419
	endtime.tv_sec -= starttime->tv_sec;
	endtime.tv_usec -= starttime->tv_usec;
	while (endtime.tv_usec < 0)
	{
		endtime.tv_usec += 1000000;
		endtime.tv_sec--;
	}
B
Bruce Momjian 已提交
420
#else							/* WIN32 */
421 422 423 424
	endtime.QuadPart -= starttime->QuadPart;
#endif

	return INSTR_TIME_GET_DOUBLE(endtime);
425
}
426 427 428

/*
 * explain_outNode -
429 430
 *	  converts a Plan node into ascii string and appends it to 'str'
 *
431 432 433 434
 * planstate points to the executor state node corresponding to the plan node.
 * We need this to get at the instrumentation data (if any) as well as the
 * list of subplans.
 *
435 436 437
 * outer_plan, if not null, references another plan node that is the outer
 * side of a join with the current node.  This is only interesting for
 * deciphering runtime keys of an inner indexscan.
438 439
 */
static void
440
explain_outNode(StringInfo str,
441
				Plan *plan, PlanState *planstate,
442
				Plan *outer_plan,
443
				int indent, ExplainState *es)
444
{
B
Bruce Momjian 已提交
445 446
	char	   *pname;
	int			i;
447 448 449

	if (plan == NULL)
	{
450
		appendStringInfoChar(str, '\n');
451 452 453 454 455
		return;
	}

	switch (nodeTag(plan))
	{
456 457 458 459 460 461
		case T_Result:
			pname = "Result";
			break;
		case T_Append:
			pname = "Append";
			break;
462 463 464 465 466 467
		case T_BitmapAnd:
			pname = "BitmapAnd";
			break;
		case T_BitmapOr:
			pname = "BitmapOr";
			break;
468
		case T_NestLoop:
469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489
			switch (((NestLoop *) plan)->join.jointype)
			{
				case JOIN_INNER:
					pname = "Nested Loop";
					break;
				case JOIN_LEFT:
					pname = "Nested Loop Left Join";
					break;
				case JOIN_FULL:
					pname = "Nested Loop Full Join";
					break;
				case JOIN_RIGHT:
					pname = "Nested Loop Right Join";
					break;
				case JOIN_IN:
					pname = "Nested Loop IN Join";
					break;
				default:
					pname = "Nested Loop ??? Join";
					break;
			}
490 491
			break;
		case T_MergeJoin:
492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512
			switch (((MergeJoin *) plan)->join.jointype)
			{
				case JOIN_INNER:
					pname = "Merge Join";
					break;
				case JOIN_LEFT:
					pname = "Merge Left Join";
					break;
				case JOIN_FULL:
					pname = "Merge Full Join";
					break;
				case JOIN_RIGHT:
					pname = "Merge Right Join";
					break;
				case JOIN_IN:
					pname = "Merge IN Join";
					break;
				default:
					pname = "Merge ??? Join";
					break;
			}
513 514
			break;
		case T_HashJoin:
515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535
			switch (((HashJoin *) plan)->join.jointype)
			{
				case JOIN_INNER:
					pname = "Hash Join";
					break;
				case JOIN_LEFT:
					pname = "Hash Left Join";
					break;
				case JOIN_FULL:
					pname = "Hash Full Join";
					break;
				case JOIN_RIGHT:
					pname = "Hash Right Join";
					break;
				case JOIN_IN:
					pname = "Hash IN Join";
					break;
				default:
					pname = "Hash ??? Join";
					break;
			}
536 537 538 539 540 541 542
			break;
		case T_SeqScan:
			pname = "Seq Scan";
			break;
		case T_IndexScan:
			pname = "Index Scan";
			break;
543 544 545 546 547 548
		case T_BitmapIndexScan:
			pname = "Bitmap Index Scan";
			break;
		case T_BitmapHeapScan:
			pname = "Bitmap Heap Scan";
			break;
549 550 551 552 553 554
		case T_TidScan:
			pname = "Tid Scan";
			break;
		case T_SubqueryScan:
			pname = "Subquery Scan";
			break;
555 556 557
		case T_FunctionScan:
			pname = "Function Scan";
			break;
558 559 560
		case T_ValuesScan:
			pname = "Values Scan";
			break;
561 562 563
		case T_Material:
			pname = "Materialize";
			break;
564 565 566 567 568 569 570
		case T_Sort:
			pname = "Sort";
			break;
		case T_Group:
			pname = "Group";
			break;
		case T_Agg:
571 572 573 574 575 576 577 578 579 580 581 582 583 584 585
			switch (((Agg *) plan)->aggstrategy)
			{
				case AGG_PLAIN:
					pname = "Aggregate";
					break;
				case AGG_SORTED:
					pname = "GroupAggregate";
					break;
				case AGG_HASHED:
					pname = "HashAggregate";
					break;
				default:
					pname = "Aggregate ???";
					break;
			}
586 587 588 589
			break;
		case T_Unique:
			pname = "Unique";
			break;
590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609
		case T_SetOp:
			switch (((SetOp *) plan)->cmd)
			{
				case SETOPCMD_INTERSECT:
					pname = "SetOp Intersect";
					break;
				case SETOPCMD_INTERSECT_ALL:
					pname = "SetOp Intersect All";
					break;
				case SETOPCMD_EXCEPT:
					pname = "SetOp Except";
					break;
				case SETOPCMD_EXCEPT_ALL:
					pname = "SetOp Except All";
					break;
				default:
					pname = "SetOp ???";
					break;
			}
			break;
610 611 612
		case T_Limit:
			pname = "Limit";
			break;
613 614 615 616
		case T_Hash:
			pname = "Hash";
			break;
		default:
617
			pname = "???";
618
			break;
619 620
	}

621
	appendStringInfoString(str, pname);
622 623
	switch (nodeTag(plan))
	{
624
		case T_IndexScan:
625
			if (ScanDirectionIsBackward(((IndexScan *) plan)->indexorderdir))
626
				appendStringInfoString(str, " Backward");
627
			appendStringInfo(str, " using %s",
B
Bruce Momjian 已提交
628
					  explain_get_index_name(((IndexScan *) plan)->indexid));
629
			/* FALL THRU */
630
		case T_SeqScan:
631
		case T_BitmapHeapScan:
632
		case T_TidScan:
633 634
			if (((Scan *) plan)->scanrelid > 0)
			{
635 636
				RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid,
											  es->rtable);
B
Bruce Momjian 已提交
637
				char	   *relname;
638 639

				/* Assume it's on a real relation */
640
				Assert(rte->rtekind == RTE_RELATION);
641 642 643

				/* We only show the rel name, not schema name */
				relname = get_rel_name(rte->relid);
644

645
				appendStringInfo(str, " on %s",
646
								 quote_identifier(relname));
647
				if (strcmp(rte->eref->aliasname, relname) != 0)
648
					appendStringInfo(str, " %s",
B
Bruce Momjian 已提交
649
									 quote_identifier(rte->eref->aliasname));
650 651
			}
			break;
652 653
		case T_BitmapIndexScan:
			appendStringInfo(str, " on %s",
654
				explain_get_index_name(((BitmapIndexScan *) plan)->indexid));
655
			break;
656 657 658 659 660 661 662
		case T_SubqueryScan:
			if (((Scan *) plan)->scanrelid > 0)
			{
				RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid,
											  es->rtable);

				appendStringInfo(str, " %s",
663
								 quote_identifier(rte->eref->aliasname));
664 665
			}
			break;
666 667 668 669 670
		case T_FunctionScan:
			if (((Scan *) plan)->scanrelid > 0)
			{
				RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid,
											  es->rtable);
671
				Node	   *funcexpr;
B
Bruce Momjian 已提交
672
				char	   *proname;
673 674 675 676

				/* Assert it's on a RangeFunction */
				Assert(rte->rtekind == RTE_FUNCTION);

677
				/*
B
Bruce Momjian 已提交
678 679 680 681
				 * If the expression is still a function call, we can get the
				 * real name of the function.  Otherwise, punt (this can
				 * happen if the optimizer simplified away the function call,
				 * for example).
682
				 */
683 684
				funcexpr = ((FunctionScan *) plan)->funcexpr;
				if (funcexpr && IsA(funcexpr, FuncExpr))
685
				{
686
					Oid			funcid = ((FuncExpr *) funcexpr)->funcid;
687 688 689 690 691 692

					/* We only show the func name, not schema name */
					proname = get_func_name(funcid);
				}
				else
					proname = rte->eref->aliasname;
693 694 695 696 697

				appendStringInfo(str, " on %s",
								 quote_identifier(proname));
				if (strcmp(rte->eref->aliasname, proname) != 0)
					appendStringInfo(str, " %s",
B
Bruce Momjian 已提交
698
									 quote_identifier(rte->eref->aliasname));
699 700
			}
			break;
701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716
		case T_ValuesScan:
			if (((Scan *) plan)->scanrelid > 0)
			{
				RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid,
											  es->rtable);
				char	   *valsname;

				/* Assert it's on a values rte */
				Assert(rte->rtekind == RTE_VALUES);

				valsname = rte->eref->aliasname;

				appendStringInfo(str, " on %s",
								 quote_identifier(valsname));
			}
			break;
717 718
		default:
			break;
719
	}
B
Bruce Momjian 已提交
720

721 722 723
	appendStringInfo(str, "  (cost=%.2f..%.2f rows=%.0f width=%d)",
					 plan->startup_cost, plan->total_cost,
					 plan->plan_rows, plan->plan_width);
724

725
	/*
B
Bruce Momjian 已提交
726 727
	 * We have to forcibly clean up the instrumentation state because we
	 * haven't done ExecutorEnd yet.  This is pretty grotty ...
728 729 730
	 */
	if (planstate->instrument)
		InstrEndLoop(planstate->instrument);
731

732 733 734
	if (planstate->instrument && planstate->instrument->nloops > 0)
	{
		double		nloops = planstate->instrument->nloops;
735

736
		appendStringInfo(str, " (actual time=%.3f..%.3f rows=%.0f loops=%.0f)",
B
Bruce Momjian 已提交
737 738
						 1000.0 * planstate->instrument->startup / nloops,
						 1000.0 * planstate->instrument->total / nloops,
739 740
						 planstate->instrument->ntuples / nloops,
						 planstate->instrument->nloops);
741
	}
742 743
	else if (es->printAnalyze)
		appendStringInfo(str, " (never executed)");
744
	appendStringInfoChar(str, '\n');
745

746
	/* quals, sort keys, etc */
747 748 749
	switch (nodeTag(plan))
	{
		case T_IndexScan:
750
			show_scan_qual(((IndexScan *) plan)->indexqualorig,
751
						   "Index Cond",
752
						   ((Scan *) plan)->scanrelid,
753
						   outer_plan, NULL,
754
						   str, indent, es);
755
			show_scan_qual(plan->qual,
756
						   "Filter",
757
						   ((Scan *) plan)->scanrelid,
758
						   outer_plan, NULL,
759 760
						   str, indent, es);
			break;
761
		case T_BitmapIndexScan:
762
			show_scan_qual(((BitmapIndexScan *) plan)->indexqualorig,
763 764
						   "Index Cond",
						   ((Scan *) plan)->scanrelid,
765
						   outer_plan, NULL,
766 767 768 769
						   str, indent, es);
			break;
		case T_BitmapHeapScan:
			/* XXX do we want to show this in production? */
770
			show_scan_qual(((BitmapHeapScan *) plan)->bitmapqualorig,
771 772
						   "Recheck Cond",
						   ((Scan *) plan)->scanrelid,
773
						   outer_plan, NULL,
774 775
						   str, indent, es);
			/* FALL THRU */
776
		case T_SeqScan:
777
		case T_FunctionScan:
778
		case T_ValuesScan:
779 780 781 782 783 784 785
			show_scan_qual(plan->qual,
						   "Filter",
						   ((Scan *) plan)->scanrelid,
						   outer_plan, NULL,
						   str, indent, es);
			break;
		case T_SubqueryScan:
786
			show_scan_qual(plan->qual,
787
						   "Filter",
788
						   ((Scan *) plan)->scanrelid,
789
						   outer_plan,
790
						   ((SubqueryScan *) plan)->subplan,
791 792
						   str, indent, es);
			break;
793 794 795 796 797 798
		case T_TidScan:
			{
				/*
				 * The tidquals list has OR semantics, so be sure to show it
				 * as an OR condition.
				 */
B
Bruce Momjian 已提交
799
				List	   *tidquals = ((TidScan *) plan)->tidquals;
800 801 802 803 804 805

				if (list_length(tidquals) > 1)
					tidquals = list_make1(make_orclause(tidquals));
				show_scan_qual(tidquals,
							   "TID Cond",
							   ((Scan *) plan)->scanrelid,
806
							   outer_plan, NULL,
807 808 809 810
							   str, indent, es);
				show_scan_qual(plan->qual,
							   "Filter",
							   ((Scan *) plan)->scanrelid,
811
							   outer_plan, NULL,
812 813 814
							   str, indent, es);
			}
			break;
815
		case T_NestLoop:
816
			show_upper_qual(((NestLoop *) plan)->join.joinqual,
817
							"Join Filter", plan,
818
							str, indent, es);
819
			show_upper_qual(plan->qual,
820
							"Filter", plan,
821 822 823
							str, indent, es);
			break;
		case T_MergeJoin:
824
			show_upper_qual(((MergeJoin *) plan)->mergeclauses,
825
							"Merge Cond", plan,
826
							str, indent, es);
827
			show_upper_qual(((MergeJoin *) plan)->join.joinqual,
828
							"Join Filter", plan,
829
							str, indent, es);
830
			show_upper_qual(plan->qual,
831
							"Filter", plan,
832 833 834
							str, indent, es);
			break;
		case T_HashJoin:
835
			show_upper_qual(((HashJoin *) plan)->hashclauses,
836
							"Hash Cond", plan,
837
							str, indent, es);
838
			show_upper_qual(((HashJoin *) plan)->join.joinqual,
839
							"Join Filter", plan,
840
							str, indent, es);
841
			show_upper_qual(plan->qual,
842
							"Filter", plan,
843 844 845 846
							str, indent, es);
			break;
		case T_Agg:
		case T_Group:
847
			show_upper_qual(plan->qual,
848
							"Filter", plan,
849 850
							str, indent, es);
			break;
851
		case T_Sort:
852
			show_sort_keys(plan,
853 854
						   ((Sort *) plan)->numCols,
						   ((Sort *) plan)->sortColIdx,
855 856
						   "Sort Key",
						   str, indent, es);
857 858
			show_sort_info((SortState *) planstate,
						   str, indent, es);
859
			break;
860 861
		case T_Result:
			show_upper_qual((List *) ((Result *) plan)->resconstantqual,
862
							"One-Time Filter", plan,
863
							str, indent, es);
864
			show_upper_qual(plan->qual,
865
							"Filter", plan,
866 867 868 869 870 871
							str, indent, es);
			break;
		default:
			break;
	}

V
Vadim B. Mikheev 已提交
872 873 874
	/* initPlan-s */
	if (plan->initPlan)
	{
875
		ListCell   *lst;
876

B
Bruce Momjian 已提交
877
		for (i = 0; i < indent; i++)
V
Vadim B. Mikheev 已提交
878 879
			appendStringInfo(str, "  ");
		appendStringInfo(str, "  InitPlan\n");
880
		foreach(lst, planstate->initPlan)
V
Vadim B. Mikheev 已提交
881
		{
882
			SubPlanState *sps = (SubPlanState *) lfirst(lst);
B
Bruce Momjian 已提交
883
			SubPlan    *sp = (SubPlan *) sps->xprstate.expr;
884

V
Vadim B. Mikheev 已提交
885 886 887
			for (i = 0; i < indent; i++)
				appendStringInfo(str, "  ");
			appendStringInfo(str, "    ->  ");
888 889
			explain_outNode(str,
							exec_subplan_get_plan(es->pstmt, sp),
890
							sps->planstate,
891
							NULL,
892
							indent + 4, es);
V
Vadim B. Mikheev 已提交
893 894
		}
	}
895 896 897 898 899 900

	/* lefttree */
	if (outerPlan(plan))
	{
		for (i = 0; i < indent; i++)
			appendStringInfo(str, "  ");
V
Vadim B. Mikheev 已提交
901
		appendStringInfo(str, "  ->  ");
B
Bruce Momjian 已提交
902

903
		/*
B
Bruce Momjian 已提交
904 905
		 * Ordinarily we don't pass down our own outer_plan value to our child
		 * nodes, but in bitmap scan trees we must, since the bottom
906 907
		 * BitmapIndexScan nodes may have outer references.
		 */
908 909
		explain_outNode(str, outerPlan(plan),
						outerPlanState(planstate),
910
						IsA(plan, BitmapHeapScan) ? outer_plan : NULL,
911
						indent + 3, es);
912
	}
913 914 915 916 917 918

	/* righttree */
	if (innerPlan(plan))
	{
		for (i = 0; i < indent; i++)
			appendStringInfo(str, "  ");
V
Vadim B. Mikheev 已提交
919
		appendStringInfo(str, "  ->  ");
920 921 922
		explain_outNode(str, innerPlan(plan),
						innerPlanState(planstate),
						outerPlan(plan),
923
						indent + 3, es);
V
Vadim B. Mikheev 已提交
924
	}
925

926
	if (IsA(plan, Append))
927
	{
928
		Append	   *appendplan = (Append *) plan;
929
		AppendState *appendstate = (AppendState *) planstate;
930
		ListCell   *lst;
931
		int			j;
932

933
		j = 0;
934 935
		foreach(lst, appendplan->appendplans)
		{
936
			Plan	   *subnode = (Plan *) lfirst(lst);
937 938 939

			for (i = 0; i < indent; i++)
				appendStringInfo(str, "  ");
940
			appendStringInfo(str, "  ->  ");
941

942 943 944
			/*
			 * Ordinarily we don't pass down our own outer_plan value to our
			 * child nodes, but in an Append we must, since we might be
B
Bruce Momjian 已提交
945 946
			 * looking at an appendrel indexscan with outer references from
			 * the member scans.
947
			 */
948 949
			explain_outNode(str, subnode,
							appendstate->appendplans[j],
950
							outer_plan,
951 952
							indent + 3, es);
			j++;
953 954
		}
	}
955

956 957
	if (IsA(plan, BitmapAnd))
	{
B
Bruce Momjian 已提交
958
		BitmapAnd  *bitmapandplan = (BitmapAnd *) plan;
959 960 961 962 963 964 965 966 967 968 969 970 971 972 973
		BitmapAndState *bitmapandstate = (BitmapAndState *) planstate;
		ListCell   *lst;
		int			j;

		j = 0;
		foreach(lst, bitmapandplan->bitmapplans)
		{
			Plan	   *subnode = (Plan *) lfirst(lst);

			for (i = 0; i < indent; i++)
				appendStringInfo(str, "  ");
			appendStringInfo(str, "  ->  ");

			explain_outNode(str, subnode,
							bitmapandstate->bitmapplans[j],
B
Bruce Momjian 已提交
974
							outer_plan, /* pass down same outer plan */
975 976 977 978 979 980 981
							indent + 3, es);
			j++;
		}
	}

	if (IsA(plan, BitmapOr))
	{
B
Bruce Momjian 已提交
982
		BitmapOr   *bitmaporplan = (BitmapOr *) plan;
983 984 985 986 987 988 989 990 991 992 993 994 995 996 997
		BitmapOrState *bitmaporstate = (BitmapOrState *) planstate;
		ListCell   *lst;
		int			j;

		j = 0;
		foreach(lst, bitmaporplan->bitmapplans)
		{
			Plan	   *subnode = (Plan *) lfirst(lst);

			for (i = 0; i < indent; i++)
				appendStringInfo(str, "  ");
			appendStringInfo(str, "  ->  ");

			explain_outNode(str, subnode,
							bitmaporstate->bitmapplans[j],
B
Bruce Momjian 已提交
998
							outer_plan, /* pass down same outer plan */
999 1000 1001 1002 1003
							indent + 3, es);
			j++;
		}
	}

1004 1005 1006
	if (IsA(plan, SubqueryScan))
	{
		SubqueryScan *subqueryscan = (SubqueryScan *) plan;
1007
		SubqueryScanState *subquerystate = (SubqueryScanState *) planstate;
1008 1009 1010 1011 1012 1013
		Plan	   *subnode = subqueryscan->subplan;

		for (i = 0; i < indent; i++)
			appendStringInfo(str, "  ");
		appendStringInfo(str, "  ->  ");

1014 1015 1016 1017
		explain_outNode(str, subnode,
						subquerystate->subplan,
						NULL,
						indent + 3, es);
1018 1019 1020
	}

	/* subPlan-s */
1021
	if (planstate->subPlan)
1022
	{
1023
		ListCell   *lst;
1024 1025 1026 1027

		for (i = 0; i < indent; i++)
			appendStringInfo(str, "  ");
		appendStringInfo(str, "  SubPlan\n");
1028
		foreach(lst, planstate->subPlan)
1029
		{
1030
			SubPlanState *sps = (SubPlanState *) lfirst(lst);
B
Bruce Momjian 已提交
1031
			SubPlan    *sp = (SubPlan *) sps->xprstate.expr;
1032

1033 1034 1035
			for (i = 0; i < indent; i++)
				appendStringInfo(str, "  ");
			appendStringInfo(str, "    ->  ");
1036 1037
			explain_outNode(str,
							exec_subplan_get_plan(es->pstmt, sp),
1038 1039
							sps->planstate,
							NULL,
1040 1041 1042
							indent + 4, es);
		}
	}
1043 1044
}

1045 1046
/*
 * Show a qualifier expression for a scan plan node
1047 1048 1049 1050
 *
 * Note: outer_plan is the referent for any OUTER vars in the scan qual;
 * this would be the outer side of a nestloop plan.  inner_plan should be
 * NULL except for a SubqueryScan plan node, where it should be the subplan.
1051 1052
 */
static void
1053
show_scan_qual(List *qual, const char *qlabel,
1054
			   int scanrelid, Plan *outer_plan, Plan *inner_plan,
1055 1056 1057
			   StringInfo str, int indent, ExplainState *es)
{
	List	   *context;
1058
	bool		useprefix;
1059 1060 1061 1062 1063 1064 1065 1066
	Node	   *node;
	char	   *exprstr;
	int			i;

	/* No work if empty qual */
	if (qual == NIL)
		return;

1067 1068
	/* Convert AND list to explicit AND */
	node = (Node *) make_ands_explicit(qual);
1069

1070 1071 1072
	/* Set up deparsing context */
	context = deparse_context_for_plan((Node *) outer_plan,
									   (Node *) inner_plan,
1073
									   es->rtable);
1074
	useprefix = (outer_plan != NULL || inner_plan != NULL);
1075 1076

	/* Deparse the expression */
1077
	exprstr = deparse_expression(node, context, useprefix, false);
1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088

	/* And add to str */
	for (i = 0; i < indent; i++)
		appendStringInfo(str, "  ");
	appendStringInfo(str, "  %s: %s\n", qlabel, exprstr);
}

/*
 * Show a qualifier expression for an upper-level plan node
 */
static void
1089
show_upper_qual(List *qual, const char *qlabel, Plan *plan,
1090 1091 1092
				StringInfo str, int indent, ExplainState *es)
{
	List	   *context;
1093
	bool		useprefix;
1094 1095 1096 1097 1098 1099 1100 1101
	Node	   *node;
	char	   *exprstr;
	int			i;

	/* No work if empty qual */
	if (qual == NIL)
		return;

1102 1103 1104
	/* Set up deparsing context */
	context = deparse_context_for_plan((Node *) outerPlan(plan),
									   (Node *) innerPlan(plan),
1105
									   es->rtable);
1106
	useprefix = list_length(es->rtable) > 1;
1107 1108 1109

	/* Deparse the expression */
	node = (Node *) make_ands_explicit(qual);
1110
	exprstr = deparse_expression(node, context, useprefix, false);
1111 1112 1113 1114 1115 1116 1117

	/* And add to str */
	for (i = 0; i < indent; i++)
		appendStringInfo(str, "  ");
	appendStringInfo(str, "  %s: %s\n", qlabel, exprstr);
}

1118 1119 1120 1121
/*
 * Show the sort keys for a Sort node.
 */
static void
1122
show_sort_keys(Plan *sortplan, int nkeys, AttrNumber *keycols,
1123
			   const char *qlabel,
1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138
			   StringInfo str, int indent, ExplainState *es)
{
	List	   *context;
	bool		useprefix;
	int			keyno;
	char	   *exprstr;
	int			i;

	if (nkeys <= 0)
		return;

	for (i = 0; i < indent; i++)
		appendStringInfo(str, "  ");
	appendStringInfo(str, "  %s: ", qlabel);

1139 1140
	/* Set up deparsing context */
	context = deparse_context_for_plan((Node *) outerPlan(sortplan),
B
Bruce Momjian 已提交
1141
									   NULL,	/* Sort has no innerPlan */
1142 1143
									   es->rtable);
	useprefix = list_length(es->rtable) > 1;
1144

1145
	for (keyno = 0; keyno < nkeys; keyno++)
1146 1147
	{
		/* find key expression in tlist */
1148
		AttrNumber	keyresno = keycols[keyno];
1149
		TargetEntry *target = get_tle_by_resno(sortplan->targetlist, keyresno);
1150

1151
		if (!target)
1152
			elog(ERROR, "no tlist entry for key %d", keyresno);
1153 1154 1155 1156 1157 1158
		/* Deparse the expression, showing any top-level cast */
		exprstr = deparse_expression((Node *) target->expr, context,
									 useprefix, true);
		/* And add to str */
		if (keyno > 0)
			appendStringInfo(str, ", ");
N
Neil Conway 已提交
1159
		appendStringInfoString(str, exprstr);
1160 1161 1162 1163
	}

	appendStringInfo(str, "\n");
}
1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185

/*
 * If it's EXPLAIN ANALYZE, show tuplesort explain info for a sort node
 */
static void
show_sort_info(SortState *sortstate,
			   StringInfo str, int indent, ExplainState *es)
{
	Assert(IsA(sortstate, SortState));
	if (es->printAnalyze && sortstate->sort_Done &&
		sortstate->tuplesortstate != NULL)
	{
		char	   *sortinfo;
		int			i;

		sortinfo = tuplesort_explain((Tuplesortstate *) sortstate->tuplesortstate);
		for (i = 0; i < indent; i++)
			appendStringInfo(str, "  ");
		appendStringInfo(str, "  %s\n", sortinfo);
		pfree(sortinfo);
	}
}
1186 1187 1188 1189 1190 1191 1192 1193 1194 1195

/*
 * 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)
{
B
Bruce Momjian 已提交
1196
	const char *result;
1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211

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